Обнаружение отключения клиента TCP - PullRequest
67 голосов
/ 12 ноября 2008

Допустим, у меня простой сервер и accept() установил соединение с клиента.

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

Ответы [ 12 ]

96 голосов
/ 16 июля 2013

В TCP есть только один способ обнаружить упорядоченное разъединение, то есть получить ноль в качестве возвращаемого значения от read()/recv()/recvXXX() при чтении.

Существует также только один надежный способ обнаружения разорванного соединения: запись в него. После достаточного количества записей в разорванное соединение TCP выполнит достаточно попыток и тайм-аутов, чтобы узнать, что оно разорвано, и в конечном итоге write()/send()/sendXXX() вернет -1 со значением errno/WSAGetLastError() ECONNRESET, или в некоторых случаях истекло время ожидания соединения ». Обратите внимание, что последний отличается от «тайм-аута соединения», который может возникнуть в фазе соединения.

Вы также должны установить разумное время ожидания для чтения и отбросить соединения, которые его терпят неудачу.

Ответ здесь о ioctl() и FIONREAD - полная ерунда. Все, что он делает, это говорит вам, сколько байтов в настоящее время находится в буфере приема сокета, доступном для чтения без блокировки. Если клиент не отправляет вам в течение пяти минут ничего, что не является разъединением, но приводит к тому, что FIONREAD будет равно нулю. Не то же самое: даже близко.

12 голосов
/ 12 ноября 2008

Подробнее об этом:

Если вы работаете с сервером, вам нужно либо использовать TCP_KEEPALIVE для мониторинга клиентских подключений, либо сделать что-то подобное самостоятельно, либо иметь знания о данных / протоколе, которые вы используете по соединению.

По сути, если соединение разрывается (то есть не закрывается должным образом), то сервер не будет замечать, пока не попытается что-то записать клиенту, что и делает keepalive для вас. В качестве альтернативы, если вы знаете протокол лучше, вы все равно можете просто отключиться по таймауту бездействия.

2 голосов
/ 12 ноября 2008

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

1 голос
/ 12 ноября 2008

select (с установленной маской чтения) вернется с сигнальным дескриптором, но когда вы используете ioctl * для проверки количества байтов, ожидающих чтения, оно будет равно нулю. Это признак того, что розетка была отключена.

Это отличное обсуждение различных методов проверки того, что клиент отключился: Стивен Клири, Обнаружение полуоткрытых (удаленных) соединений .

* для Windows используйте ioctlsocket.

0 голосов
/ 05 октября 2017

Возвращаемое значение приема будет -1, если соединение потеряно, иначе это будет размер буфера.

void ReceiveStream(void *threadid)
{
    while(true)
    {
        while(ch==0)
        {
            char buffer[1024];
            int newData;
            newData = recv(thisSocket, buffer, sizeof(buffer), 0);
            if(newData>=0)
            {
                std::cout << buffer << std::endl;
            }
            else
            {
                std::cout << "Client disconnected" << std::endl;
                if (thisSocket)
                {
                    #ifdef WIN32
                        closesocket(thisSocket);
                        WSACleanup();
                    #endif
                    #ifdef LINUX
                        close(thisSocket);
                    #endif
                }
                break;
            }
        }
        ch = 1;
        StartSocket();
    }
}
0 голосов
/ 19 июля 2016

TCP имеет процедуры «открыть» и «закрыть» в протоколе. После «открытия» соединение удерживается до «закрытия». Но есть много вещей, которые могут ненормально остановить поток данных. При этом методы определения возможности использования канала связи в значительной степени зависят от уровней программного обеспечения между протоколом и прикладной программой. Упомянутые выше фокусируются на программисте, пытающемся использовать сокет неинвазивным способом (чтение или запись 0 байтов), возможно, наиболее распространенными. Некоторые слои в библиотеках обеспечат «опрос» для программиста. Например, асинхронные (отложенные) вызовы Win32 могут начать чтение, которое будет возвращаться без ошибок и 0 байтов, чтобы сигнализировать сокет, который больше не может быть прочитан (предположительно процедура TCP FIN). Другие среды могут использовать «события», как определено в их слоях упаковки. На этот вопрос нет однозначного ответа. Механизм обнаружения случаев, когда сокет не может использоваться и должен быть закрыт, зависит от упаковщиков, поставляемых в библиотеках. Также стоит отметить, что сами сокеты могут повторно использоваться слоями под библиотекой приложений, поэтому разумно выяснить, как ваша среда взаимодействует с интерфейсом сокетов Berkley.

0 голосов
/ 21 декабря 2015

Попробуйте поискать EPOLLHUP или EPOLLERR. Как проверить, что клиентское соединение еще живо

Чтение и поиск 0 будут работать в некоторых случаях, но не во всех.

0 голосов
/ 27 июля 2014

Мы сталкиваемся с подобной проблемой, когда обнаружение удаления кабеля на ПК было проблемой. После поиска в Google мы обратились к библиотеке SuperCom for TCP, которая предлагала эту функцию, и к очень надежной библиотеке передачи данных, которая также могла обрабатывать сообщения о событиях при закрытии соединения.

0 голосов
/ 16 июля 2013

Я играл с несколькими решениями, но, похоже, это лучше всего подходит для обнаружения отключения хоста и / или клиента в Windows. Он предназначен для неблокирующих сокетов и основан на примере IBM .

char buf;
int length=recv(socket, &buf, 0, 0);
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0){
    return 0;
}   
if (nError==0){
    if (length==0) return 0;
}
0 голосов
/ 07 декабря 2009

апрельская библиотека из проекта apache - хороший справочник для этой проблемы. Он использует опрос со значением тайм-аута, чтобы проверить, разорвано ли соединение с другой стороны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...