簡體   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