[英]Telnet Blocking C# TCP Server
我正在用C#语言编写一个TCP服务器,并且遇到了一个奇怪的问题,也可能是一个安全问题。
我接受新连接的基本方法如下:
AcceptAsync
方法接受传入的连接。 ThreadPool
接受的连接以完成接受。 一切正常,但是如果有人通过telnet进入端口,一切都会停顿下来。
症状:
如果我通过telnet进入服务器并且不发送任何数据(即不按任何键),则服务器将永远无法完成接受连接。
telnet连接永远不会命中我的SocketAsyncEventArgs.Completed
回调。
更糟糕的是,所有其他连接都被阻止/排队,并且永远不会被我的代码接受。 它们被置于CLOSE_WAIT
状态:
TCP 127.0.0.1:8221 chance:53960 CLOSE_WAIT
TCP 127.0.0.1:8221 chance:53962 CLOSE_WAIT
TCP 127.0.0.1:8221 chance:53964 CLOSE_WAIT
任何意见,将不胜感激。
StartAccept:
private void StartAccept(SocketAsyncEventArgs AcceptArgs)
{
CurrentAcceptArgs = AcceptArgs;
AcceptArgs.AcceptSocket = null;
if (AcceptArgs.Buffer == null ||
AcceptArgs.Buffer.Length < 1024)
{
AcceptArgs.SetBuffer(new byte[1024], 0, 1024);
}
if (MainSocket != null)
{
lock (MainSocket)
{
// If this is false, we have an accept waiting right now, otherwise it will complete aynsc
if (MainSocket.AcceptAsync(AcceptArgs) == false)
{
ThreadPool.QueueUserWorkItem(FinishAccept, AcceptArgs);
StartAccept(GetConnection());
}
}
}
}
完成用于接受连接的回调:
protected override void OnIOCompleted(object sender, SocketAsyncEventArgs e)
{
PWClientRemote RemoteClient = e.UserToken as PWClientRemote;
// Determine which type of operation just completed and call the associated handler.
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
StartAccept(GetConnection());
ThreadPool.QueueUserWorkItem(FinishAccept, e);
break;
default:
base.OnIOCompleted(sender, e);
break;
}
}
完成接受:
private void FinishAccept(object StateObject)
{
SocketAsyncEventArgs args = (SocketAsyncEventArgs)StateObject;
FinishAcceptInternal(args);
}
这是从连接telnet到发送数据之前的Wireshk:
No. Time Source Destination Protocol Length Info
1 0.000000 192.168.1.146 192.168.1.109 TCP 66 59766 > 8221 [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
2 0.000076 192.168.1.109 192.168.1.146 TCP 66 8221 > 59766 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
3 0.000389 192.168.1.146 192.168.1.109 TCP 60 59766 > 8221 [ACK] Seq=1 Ack=1 Win=65536 Len=0
这应该是建立我的连接的完整握手,但是从不引发Completed
事件。
当我找到了潜在的原因时,回答我自己的问题:
错误是此行:
if (AcceptArgs.Buffer == null ||
AcceptArgs.Buffer.Length < 1024)
{
AcceptArgs.SetBuffer(new byte[1024], 0, 1024);
}
这是因为如果设置了缓冲区,AcceptAsync将阻塞直到接收到一些数据。
从MSDN :
所需的最小缓冲区大小为288个字节。 如果指定了更大的缓冲区大小,则套接字将期望一些额外的数据,而不是Winsock AcceptEx调用接收到的地址数据,并且将等待直到接收到该额外数据。
我更正的代码:
// We set a null buffer here.
// If we set a valid buffer, the accept will expect data
// and will hang unless it gets it.
AcceptArgs.SetBuffer(null, 0, 0);
我不确定这是否是正确的解决方法,设置288字节或更小的缓冲区似乎无法解决此问题。 仅将缓冲区设置为null会导致在不发送数据的连接时引发Completed
事件。
看起来GetConnection被阻止在某处。 通常,如果服务器不承受重负载,则异步操作可能以同步方式完成。 同样,调用AcceptAsync返回false或回调方法这一事实意味着异步操作已完成,您的代码应分析结果。
下面是一个简单的异步TCP服务器框架,它可以异步接受连接。
void StartServer()
{
Socket serverSocket = new Socket(addr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(addr, port));
s.Listen(5000);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptCompleted);
args.UserToken = serverSocket;
if ( !serverSocket.AcceptAsync(args) )
AcceptCompleted(this, args);
}
void AcceptCompleted(object obj, SocketAsyncEventArgs args)
{
Socket client = args.AcceptSocket;
if (args.SocketError != SocketError.Success)
return;
StartClientOperations(args.AcceptSocket);
args.AcceptSocket = null;
Socket s = (Socket)args.UserToken;
if (!s.AcceptAsync(args))
AcceptCompleted(this, args);
}
void StartClientOperations(Socket newClient)
{
//start other asynchronous operations here with the client socket
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.