繁体   English   中英

Telnet阻止C#TCP服务器

[英]Telnet Blocking C# TCP Server

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

我接受新连接的基本方法如下:

  1. AC#套接字在端口上侦听,使用AcceptAsync方法接受传入的连接。
  2. 使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM