#c #sockets #timeout #sendto
#c #сокеты #тайм-аут #отправить
Вопрос:
Как я могу повторить попытку отправки (скажем, используя цикл while или что-то подобное) в следующем коде, который у меня есть, всякий раз, когда у меня есть тайм-аут? Я сократил некоторые части своего кода.
Я не знаком с кодами ошибок C и обработкой ошибок, поэтому я не знаю, где перехватывать / обрабатывать ошибку и какой код ошибки искать.
sock = socket(create socket....)
if (sock < 0 ) {
exit(EXIT_FAILURE);
}
servaddr initializations.....
sendto(sock, etc etc........);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,amp;timeout,sizeof(timeout)) < 0) {
perror("Error");
}
addrlen = sizeof(servaddr);
if(recvfrom (sock, etc, etc......) < 0)
{
printf("revfrom failed.n");
}
Комментарии:
1. Что вы имеете в виду под «как я мог бы создать повторную попытку»? Просто проверьте возвращаемое значение и повторно выполните системный вызов, если он завершится неудачей. В чем проблема с этим?
2. Извините, я имел в виду, как я могу повторить отправку, если есть тайм-аут. Я не могу понять, где в моем коде я могу вставить цикл.
3.
recvfrom
устанавливаетerrno
значениеEAGAIN
илиEWOULDBLOCK
, если сбой произошел из-за истечения времени ожидания.
Ответ №1:
От man 7 socket
:
SO_RCVTIMEO
иSO_SNDTIMEO
:Укажите время ожидания приема или отправки до сообщения об ошибке. Аргументом является a
struct timeval
. Если функция ввода или вывода блокируется в течение этого периода времени, и данные были отправлены или получены, возвращаемым значением этой функции будет объем переданных данных; если данные не были переданы и время ожидания было достигнуто, то-1
возвращаетсяerrno
значениеEAGAIN
илиEWOULDBLOCK
, илиEINPROGRESS
(дляconnect(2)
)точно так же, как если бы сокет был указан как неблокирующий. Если тайм-аут установлен на ноль (по умолчанию), то операция никогда не будет тайм-аута. Тайм-ауты действуют только для системных вызовов, которые выполняют ввод-вывод сокета (например,read(2)
,recvmsg(2)
,send(2)
,sendmsg(2)
); тайм-ауты не влияют наselect(2)
,poll(2)
,epoll_wait(2)
, и так далее.
Итак, в вашем случае код для продолжения попыток при достижении тайм-аута будет выглядеть примерно так:
struct timeval timeout = {.tv_sec = 5, .tv_usec = 0};
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, amp;timeout, sizeof(timeout)) < 0) {
perror("setsockopt failed");
// Handle error
}
// ...
while (sendto(sock, /*...*/) == -1) {
if (errno != EAGAIN amp;amp; errno != EWOULDBLOCK) {
// Some unexpected error happened.
perror("sendto failed");
}
// Otherwise it was a timeout, just continue trying.
}
Обратите внимание, что SO_SNDTIMEO
это для отправки и SO_RCVTIMEO
для получения. Если вы хотите установить оба, выполните два setsockopt
вызова.
В любом случае, мне кажется, что вы тратите свое время на это. Если вы хотите продолжать попытки, пока не получите данные, тогда просто не беспокойтесь о каких-либо setsockopt
действиях, поскольку поведение по умолчанию заключается в том, чтобы ждать неопределенно долго, пока не будут получены данные:
Если тайм-аут установлен на ноль (по умолчанию), то операция никогда не будет тайм-аута.