Как я могу проверить, отключен ли клиент через Winsock в C ++? - PullRequest
12 голосов
/ 26 марта 2009

Как я могу проверить, отключен ли клиент через Winsock в C ++?

Ответы [ 4 ]

12 голосов
/ 26 марта 2009

Руководство по сетевому программированию Beej

если вы вызываете recv в режиме блокировки и он возвращает с прочитанными 0 байтами, сокет отключился, иначе он ожидает получения байтов.

Посмотрите в этом FAQ 2.12

пример из выбора на этой странице.

int nRet;

if(( nRet = select( 0, &fdread, NULL, NULL, NULL )) == SOCKET_ERROR )
{
    // Error condition
    // Check WSAGetLastError
}

if( nRet > 0 )
{
    // select() will return value 1 because i m using only one socket
    // At this point, it should be checked whether the
    // socket is part of a set.

    if( FD_ISSET( s, &fdread ))
    {
        // A read event has occurred on socket s
    }
}
5 голосов
/ 26 марта 2009

Вы можете только сказать, отключен ли TCP-сокет, пытаясь отправить данные. Это связано с тем, что структура протокола такова, что он допускает временные перебои между узлами. Таким образом, если вы подключаетесь из A через R1 через R2 через R3 к B и некоторое время отправляете данные, а затем прекращаете отправку, вы можете отключить R2-> R3 (например), и ни A, ни B не заметят (или не позаботятся). Если вы затем подключите R2-> R4 и R4-> R3, а затем попытаетесь передать данные между A и B, то все будет «просто работать», и вы никогда не узнаете. Однако, если вы попытались отправить данные, когда R2-> R3 был отключен, вы (в конце концов, после всех попыток уровня TCP) вернули ошибку.

Теперь некоторые операционные системы могут предупреждать вас о том, что ваш локальный сетевой адаптер в данный момент не подключен, и вы можете использовать это, чтобы сказать: «Я больше не подключен к своим партнерам», но я бы не стал посоветуйте это.

Если важно, чтобы ваши одноранговые узлы знали, когда соединения «разорваны», то либо используйте сообщение ping уровня приложения для периодической отправки данных между одноранговыми узлами, либо используйте поддержку активности TCP. Лично я бы пошел на пинг сообщения ...

Редактировать: Конечно, все, что предполагает, что вы хотите знать, можете ли вы по-прежнему отправлять данные по соединению, в конце концов, вам СКАЗАНО, когда клиент больше не отправляет, потому что ваши чтения будут верните 0 байт, и вы ЗНАЕТЕ, когда он отсоединяет свою отправляющую сторону, потому что ваши записи не будут выполнены; Вы также ЗНАЕТЕ, когда выключаете сторону отправки или получения своего собственного конца соединения ...

Полагаю, я должен был придерживаться первоначальной реакции кишечной реакции "определить отключен";)

2 голосов
/ 26 марта 2009

Существует несколько различных способов, но наиболее распространенным является проверка результата команды отправки или получения:

 nReadBytes = recv(sd, ReadBuffer, BufferSize, 0);
 if (nReadBytes == SOCKET_ERROR)
 {
     //error
 }
 nSendBytes = send(sd, WriteBuffer, BufferSize, 0);
 if (nSendBytes == SOCKET_ERROR)
 {
     //error
 }

Дополнительные примеры (в комплекте с проверкой ошибок, как клиента, так и сервера) здесь:

http://tangentsoft.net/wskfaq/examples/basics/

0 голосов
/ 27 ноября 2013

Если результат send () или recv () равен SOCKET_ERROR и WSAGetLastError () возвращает WSAECONNRESET, клиент отключен. Из MSDN:

WSAECONNRESET

Сброс соединения по пиру.

Существующее соединение было принудительно закрыто удаленным хостом. это обычно получается, если одноранговое приложение на удаленном хосте внезапно остановился, хост перезагружен, хост или удаленная сеть Интерфейс отключен, или удаленный хост использует жесткое закрытие (см. setsockopt для получения дополнительной информации о опции SO_LINGER на пульте разъем). Эта ошибка также может произойти, если соединение было разорвано из-за активность активности при обнаружении сбоя во время одной или нескольких операций в процессе. Операции, которые выполнялись, терпят неудачу с WSAENETRESET. Последующие операции завершаются неудачно с WSAECONNRESET.

Это также работает с неблокирующими сокетами.

int r = recv(sock, NULL, 0, 0);
if(r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET){
    //client has disconnected!
}
...