Как найти состояние подключения сокета в C? - PullRequest
24 голосов
/ 10 ноября 2010

У меня TCP-соединение. Сервер просто читает данные с клиента. Теперь, если соединение потеряно, клиент получит ошибку при записи данных в канал (поврежденный канал), но сервер все еще прослушивает этот канал. Могу ли я узнать, работает ли соединение UP или нет?

Ответы [ 9 ]

33 голосов
/ 10 ноября 2010

Вы можете вызвать getsockopt так:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);

Для проверки работоспособности розетки:

if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
    return;
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}
11 голосов
/ 10 ноября 2010

Единственный способ надежно определить, подключен ли сокет, - периодически пытаться отправить данные. Обычно удобнее определить пакет ping уровня приложения, который клиенты игнорируют, но если протокол уже не задействован без такой возможности, вы сможете настроить сокеты tcp для этого, установив SO_KEEPALIVE вариант сокета. Я связался с документацией по winsock, но такая же функциональность должна быть доступна для всех стеков сокетов, подобных BSD.

4 голосов
/ 10 ноября 2010

Опция сокета keepalive TCP (SO_KEEPALIVE) поможет в этом сценарии и закроет сокет сервера в случае потери соединения.

2 голосов
/ 02 октября 2012

У меня была похожая проблема.Я хотел знать, подключен ли сервер к клиенту или клиент подключен к серверу.В таких случаях возвращаемое значение функции recv может пригодиться.Если сокет не подключен, он вернет 0 байтов.Таким образом, используя это, я разорвал цикл и не нуждался в дополнительных потоках функций.Вы можете также использовать это, если эксперты считают, что это правильный метод.

1 голос
/ 11 июля 2016

Существует простой способ проверить состояние соединения через сокет poll. Во-первых, вам нужно опросить сокет, имеет ли он событие POLLIN.

  1. Если сокет не закрыт и есть данные для чтения, то read вернет больше нуля.
  2. Если в сокете нет новых данных, то POLLIN будет установлено в 0 в revents
  3. Если сокет закрыт, то флаг POLLIN будет установлен в единицу, и чтение вернет 0.

Вот небольшой фрагмент кода:

int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s1");
    abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s2");
    abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024]; 
while (true)
{
    poll(pfd,2,5);
    if (pfd[0].revents & POLLIN)
    {
        int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_2, sock_buf, sock_readden);
    }
    if (pfd[1].revents & POLLIN)
    {
        int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_1, sock_buf, sock_readden);
    }
}
1 голос
/ 03 февраля 2014

Вы должны попытаться использовать: getpeername function.

теперь, когда соединение разорвано, вы получите сообщение об ошибке: ENOTCONN - Разъем не подключен. что означает для вас ВНИЗ.

else (если нет других сбоев), там код возврата будет 0 ->, что означает UP.

ресурсы: Страница man: http://man7.org/linux/man-pages/man2/getpeername.2.html

1 голос
/ 13 декабря 2013

get sock opt может быть несколько полезным, однако другим способом будет установить обработчик сигнала для SIGPIPE.Как правило, всякий раз, когда у вас разрывается сокетное соединение, ядро ​​отправляет сигнал SIGPIPE процессу, а затем вы можете сделать все необходимое.Но это все еще не обеспечивает решение для знания статуса соединения.надеюсь, это поможет.

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

Вы можете использовать макрос SS_ISCONNECTED в функции getsockopt(). SS_ISCONNECTED определяется в socketvar.h.

0 голосов
/ 10 ноября 2010

Для сокетов BSD я бы проверил Руководство Биджа .Когда recv возвращает 0, вы знаете, что другая сторона отключена.

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

...