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

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

4 ответов


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

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

посмотреть в этой FAQ 2.12

пример из select on этой страница.

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
    }
}

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

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

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

Edit: конечно, все это предполагает, что вы хотите знать, можете ли вы по-прежнему отправлять данные о соединении, в конце концов, вам говорят, когда клиент больше не отправляет, потому что ваши чтения вернут 0 байт, и вы знаете, когда он отключает свою отправляющую сторону, потому что ваши записи не удастся; вы также знаете, когда вы выключите либо отправку, либо recv сторону вашего собственного конца соединения...

Я думаю, что я должен был застрять с первоначальной реакцией кишечника на "define disconnected";)


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

 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/


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

WSAECONNRESET

Соединение прервано.

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

Это также работает с non преграждая гнездами.

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