Как уже упоминалось, вы можете использовать select (), чтобы установить ограничение времени чтения сокета.
По умолчанию сокет станет читаемым, если в приемном буфере сокета будет доступен один или несколько байтов. Я говорю «по умолчанию», потому что это количество можно изменить, установив для буфера приема сокета «низкую отметку» с помощью параметра сокета SO_RCVLOWAT.
Ниже приведена функция, которую вы можете использовать, чтобы определить, готов ли сокет к чтению в течение определенного периода времени. Он вернет 1, если в сокете есть данные, доступные для чтения. В противном случае он вернет 0, если истечет время ожидания.
Код основан на примере из книги «Сетевое программирование Unix» (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 ()?