[英]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.