Как обнаружить разъединение TCP-сокета (с сокетом C Berkeley) - PullRequest
9 голосов
/ 19 июня 2011

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

while(true) {
            bzero(buffer,256);
            n = read(newsockfd,buffer,255);
            printf("%s\n",buffer);        
}

Ответы [ 3 ]

16 голосов
/ 19 июня 2011

Единственный способ определить, что сокет подключен, - записать в него.

Ошибка на read()/recv() будет означать, что соединение разорвано, но ошибка не возникает, когда чтение не 't означает, что соединение установлено.

Вам может быть интересно прочитать это: http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html

Кроме того, использование TCP Keep Alive может помочь различать неактивные и неактивныеразорванные соединения (отправка чего-либо через равные промежутки времени, даже если приложение не отправляет данные).

(РЕДАКТИРОВАТЬ: удалено неправильное предложение, как указано @Damon, спасибо.)

0 голосов
/ 21 февраля 2017

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

if (n == 0) // peer disconnected
    break;
else if (n == -1) // error
{
    perror("read");
    break;
}
else // received 'n' bytes
{
    printf("%.*s", n, buffer);
}

И принятие нового соединения должно быть сделано в отдельном потоке, не зависящем от завершения потока на этом соединении.

Вызов bzero() не имеет смысла, это просто обход предыдущих ошибок.

0 голосов
/ 25 января 2016

Это потому, что вы не использовали keepalive timeout. На принимающей стороне опция сокета keepalive - лучшее решение для обнаружения разрыва соединения.

Но, если ваше приложение продолжит писать в сокет, есть над чем подумать. Даже если вы уже установили опцию keepalive для сокета своего приложения, вы не можете вовремя обнаружить состояние разрыва соединения сокета, если ваше приложение продолжает писать в сокет. Это из-за повторной передачи tcp стеком tcp ядра. tcp_retries1 и tcp_retries2 являются параметрами ядра для настройки времени ожидания повторной передачи tcp. Трудно предсказать точное время ожидания повторной передачи, потому что оно рассчитывается по механизму RTT. Вы можете увидеть это вычисление в rfc793. (3.7. Передача данных)

https://www.rfc -editor.org / rfc / rfc793.txt

Каждая платформа имеет конфигурации ядра для повторной передачи tcp.

Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4)

http://linux.die.net/man/7/tcp

HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval

http://www.hpuxtips.es/?q=node/53

AIX : rto_low, rto_high, rto_length, rto_limit

http://www -903.ibm.com / кр / событие / загрузить / 200804_324_swma / socket.pdf

Вам следует установить более низкое значение для tcp_retries2 (по умолчанию 15), если вы хотите раннее обнаружение разорванного соединения, но это не точное время, как я уже сказал. Кроме того, в настоящее время вы не можете установить эти значения только для одного сокета. Это глобальные параметры ядра. Было несколько попыток применить опцию сокета повторной передачи tcp для одного сокета (http://patchwork.ozlabs.org/patch/55236/),, но я не думаю, что он был применен к основному ядру ядра. Я не могу найти определение этих опций в заголовочных файлах системы.

Для справки, вы можете отслеживать опцию keepalive через «netstat --timers», как показано ниже. https://stackoverflow.com/questions/34914278

netstat -c --timer | grep "192.0.0.1:43245             192.0.68.1:49742"

tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (1.92/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (0.71/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (9.46/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (8.30/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (7.14/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (5.98/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (4.82/0/1)

Кроме того, при возникновении тайм-аута keepalive вы можете встретить различные события возврата в зависимости от используемых вами платформ, поэтому вы не должны определять состояние разорванного соединения только событиями возврата. Например, HP возвращает событие POLLERR, а AIX возвращает только событие POLLIN, когда происходит тайм-аут keepalive. В это время вы встретите ошибку ETIMEDOUT в вызове recv ().

В последней версии ядра (начиная с 2.6.37), вы можете использовать опцию TCP_USER_TIMEOUT, которая будет работать хорошо. Эта опция может быть использована для одного сокета.

...