Блокирование recv вызов зависает, если сервер снижается

Другая проблема разъема.

В моем клиентском коде я отправляю некоторый пакет и ожидаю некоторый ответ от стороны сервера:


отправьте ()

recv () <-это блокируется

Сразу после отправляют (), катастрофические отказы сервера и перезагрузил себя. Тем временем recv () ожидает. Но даже после того, как сервер возрос, принимать вызов зависает. Я добавил обработку сигнала SIGPIPE, но ее все еще не способный распознать, что сокет повреждается.

Когда я отменяю операцию, я получил ошибку от recv (), что прерывание было выпущено.

Кто-либо мог помочь мне, как исправить эту ошибку?

Это находится в общей библиотеке, работающей на машине Соляриса.

6
задан Michael Petrotta 31 July 2011 в 00:48
поделиться

4 ответа

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

По умолчанию сокет становится доступным для чтения, когда в приемном буфере сокета есть один или несколько байтов. Я говорю «по умолчанию», потому что это количество можно настроить, установив для буфера приема сокета «нижнюю отметку» с помощью параметра сокета SO_RCVLOWAT.

Ниже приведена функция, с помощью которой можно определить, готов ли сокет к чтению в течение заданного периода времени. Он вернет 1, если в сокете есть данные, доступные для чтения. В противном случае он вернет 0, если истечет время ожидания.

Код основан на примере из книги Unix Network Programming (www.unpbook.com), который может предоставить вам дополнительную информацию.

/* Wait for "timeout" seconds for the socket to become readable */
readable_timeout(int sock, int timeout)
{
    struct timeval tv;
    fd_set         rset;
    int            isready;

    FD_ZERO(&rset);
    FD_SET(sock, &rset);

    tv.tv_sec  = timeout;
    tv.tv_usec = 0;

 again:
    isready = select(sock+1, &rset, NULL, NULL, &tv);
    if (isready < 0) {
        if (errno == EINTR) goto again;
        perror("select"); _exit(1);
    }

    return isready;
}

Используйте это так:

if (readable_timeout(sock, 5/*timeout*/)) {
    recv(sock, ...)

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

Причина может заключаться в том, что сервер аварийно завершает работу и перезагружается, теряя свое состояние TCP. Ваш клиент отправляет данные на сервер, который отправляет обратно RST, поскольку у него больше нет состояния для подключения. Ваш клиент игнорирует RST и пытается отправить больше данных, и именно этот второй send () заставляет вашу программу получать сигнал SIGPIPE.

Какую ошибку вы получили при вызове recv ()?

4
ответ дан 8 December 2019 в 16:02
поделиться

May be you should set a timeout delay in order to manage this case. It can easily done by using setsockopt and setting SO_RECVTIMEO flag on your socket:

  struct timeval tv;
  tv.tv_sec = 30;
  tv.tv_usec = 0;
  if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof tv))
  {
    perror("setsockopt");
    return -1;
  }

Another possibility is to use non blocking sockets and manage read/write stuff with poll(2) or select(2). You should take a look on Beej's Guide to Network Programming.

6
ответ дан 8 December 2019 в 16:02
поделиться

The problem is that the connection is never actually closed. (No FIN packages are sent etc, the other end just goes away.)

What you want to do is set a timeout for recv'ing on the socket, using setsockopt(3) with SO_RCVTIMEO as option_name.

3
ответ дан 8 December 2019 в 16:02
поделиться

Другой способ сделать вызов recv() неблокируемым на Solaris - использовать fcntl() для установки неблокирующего дескриптора сокета:

fcntl(sockDesc, F_SETFL, O_NONBLOCK);

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

2
ответ дан 8 December 2019 в 16:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: