Модель WSAEventSelect - PullRequest
       6

Модель WSAEventSelect

1 голос
/ 25 августа 2009

Эй, я использую WSAEventSelect для уведомлений о событиях сокетов. Пока все круто и работает как шарм, но есть одна проблема.

Клиент - это приложение .NET, а сервер написан на Winsock C ++. В приложении .NET я использую класс System.Net.Sockets.Socket для TCP / IP. Когда я вызываю методы Socket.Shutdown () и Socket.Close (), я получаю событие FD_CLOSE на сервере, которое, я уверен, в порядке. Хорошо, проблема возникает, когда я проверяю iErrorCode WSANETWORKEVENTS, который я передал WSAEnumNetworkEvents. Я проверяю это так

if (listenerNetworkEvents.lNetworkEvents & FD_CLOSE)
    {
        if (listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
        {
            // it comes here
            // which means there is an error
            // and the ERROR I got is
            // WSAECONNABORTED
            printf("FD_CLOSE failed with error %d\n", 
                listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT]);
            break;
        }

        closesocket(socketArray[Index]);
}

Но происходит сбой с ошибкой WSAECONNABORTED . Почему это так?

РЕДАКТИРОВАТЬ: Кстати, я работаю и клиент и сервер на одном компьютере, это из-за этого? И я получил событие FD_CLOSE, когда я делаю это:

server.Shutdown(SocketShutdown.Both);   // in .NET C#, client code

1 Ответ

2 голосов
/ 25 августа 2009

Я предполагаю, что вы вызываете Shutdown (), а затем Close () сразу после этого. Это даст симптом, который вы видите, потому что это «захлопывание соединения». Shutdown () инициирует постепенное отключение (TCP FIN), но сразу же после него с помощью Close () прерывает это, отправляя пакет TCP RST удаленному узлу. Ваш вызов Shutdown (SocketShutdown.Both), кстати, тоже захлопывает закрытое соединение.

Правильный шаблон:

  1. Call Shutdown () с параметром направления, установленным на «запись», что означает, что мы больше не будем отправлять данные на удаленный узел. Это заставляет стек отправлять пакет TCP FIN.

  2. Вернемся к ожиданию событий Winsock. Когда удаленный узел также завершит запись, он также вызовет Shutdown («запись»), в результате чего его стек отправит вашей машине пакет TCP FIN, а ваше приложение получит событие FD_CLOSE. Во время ожидания ваш код должен быть готов продолжить чтение из сокета, поскольку удаленный узел все еще может отправлять данные.

(Прошу прощения за псевдо-C # выше. Я не говорю на .NET, только на C ++.)

Ожидается, что оба узла будут использовать один и тот же шаблон выключения: каждый сообщает другому, когда завершит запись, а затем ожидает получения уведомления о том, что удаленный узел завершил запись, прежде чем он закроет свой сокет.

Важно понимать, что TCP - это двунаправленный протокол: каждая сторона может отправлять и получать независимо от другой. Закрытие сокета для чтения не очень хорошая вещь. Это похоже на разговор с другим человеком, но только разговор и нежелание слушать. Изящный протокол выключения говорит: «Я уже разговаривал. Я подожду, пока ты перестанешь говорить, прежде чем я уйду».

...