Блокировка Telnet C # TCP Server - PullRequest
       37

Блокировка Telnet C # TCP Server

1 голос
/ 17 января 2012

Я пишу TCP-сервер на C # и столкнулся со странной и, возможно, проблемой безопасности.

Моя основная арка для приема новых соединений выглядит следующим образом:

  1. AC # прослушивание сокета через порт с использованием метода AcceptAsync для приема входящих соединений.
  2. Отключение принятых соединений с использованием ThreadPool для завершения приема.

Все работает довольно хорошо, однако все останавливается, если кто-то подключается к порту.

Симптомы:

  • Если я telnet на свой сервер и не отправляю никаких данных (т.е. не нажимаю какие-либо ключи), сервер никогда не завершит прием соединения.

  • Мой SocketAsyncEventArgs.Completed обратный вызов никогда не срабатывает для соединения через telnet.

  • Еще хуже, все дальнейшие соединения блокируются / ставятся в очередь и никогда не получатпринят по моему коду.Они переводятся в состояние 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;
    }
}

Finish Accept:

private void FinishAccept(object StateObject)
{
    SocketAsyncEventArgs args = (SocketAsyncEventArgs)StateObject;
    FinishAcceptInternal(args);
}

Вот проводник от соединенияtelnet, но перед отправкой данных:

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 никогда не возникает.

Ответы [ 2 ]

1 голос
/ 17 января 2012

Отвечая на мой собственный вопрос, я нашел причину:

Ошибка в этой строке:

if (AcceptArgs.Buffer == null ||
    AcceptArgs.Buffer.Length < 1024)
{
    AcceptArgs.SetBuffer(new byte[1024], 0, 1024);
}

Это потому, что если вы установите буфер, AcceptAsync будет блокироваться, пока не получит некоторые данные.

С MSDN :

Минимальный требуемый размер буфера составляет 288 байт. Если указан больший размер буфера, то Socket будет ожидать каких-то дополнительных данных, кроме адресных данных, полученных вызовом 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 при подключении без отправки данных.

0 голосов
/ 17 января 2012

Похоже, что 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
}
...