gpt4 book ai didi

c# - Telnet 阻塞 C# TCP 服务器

转载 作者:可可西里 更新时间:2023-11-01 02:52:50 25 4
gpt4 key购买 nike

我正在用 C# 编写一个 TCP 服务器,遇到了一个奇怪的问题,而且可能是一个安全问题。

我接受新连接的基本架构如下:

  1. 监听端口的 C# 套接字,使用 AcceptAsync 方法接受传入连接。
  2. 使用 ThreadPool 分离已接受的连接以完成接受。

一切都运行良好,但是如果有人 telnet 到端口,一切都会停止。

症状:

  • 如果我 telnet 到我的服务器并且不发送任何数据(即不按任何键),服务器将永远不会完成接受连接。

  • 我的 SocketAsyncEventArgs.Completed 回调从未针对 telnet 连接命中。

  • 更糟糕的是,所有进一步的连接都被阻止/排队并且永远不会被我的代码接受。它们被置于 CLOSE_WAIT 状态:

    TCP 127.0.0.1:8221 机会:53960 CLOSE_WAIT

    TCP 127.0.0.1:8221 chance:53962 CLOSE_WAIT

    TCP 127.0.0.1:8221 chance:53964 CLOSE_WAIT

如有任何建议,我们将不胜感激。

开始接受:

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 但在发送数据之前的 wireshark:

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 :

The minimum buffer size required is 288 bytes. If a larger buffer size is specified, then the Socket will expect some extra data other than the address data received by the Winsock AcceptEx call and will wait until this extra data is received.

我更正的代码:

// 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 事件。

关于c# - Telnet 阻塞 C# TCP 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8887190/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com