Если вы хотите установить сокетную связь с тайм-аутами, тогда вам нужно использовать select
.
Вы в основном настраиваете массивы файловых дескрипторов для различных событий, таких как готовность к чтению или возможность записи, затем вызываете select
с таймаутом. Если одно из событий действительно, вы будете уведомлены и сможете выполнить свои действия.
Если ни одно из событий не произойдет до истечения времени ожидания, вы все равно будете уведомлены и сможете предпринять любые корректирующие действия, которые сочтете нужным.
См. здесь для подробностей, подробно изложенных ниже.
В качестве альтернативы, вы можете использовать setsockopt
с SO_RCVTIMEO:
struct timeval tv;
tv.tv_sec = 5;
tv.tv_used = 0;
setsockopt (socket_id, SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(struct timeval));
Для получения подробной информации о select
вы используете макросы FD_ZERO
и FD_SET
для создания интересующего вас набора файловых дескрипторов (fdsets). У вас может быть три набора: один, указывающий, есть ли у одного или нескольких fds данные для чтения, один, указывающий, готов ли один или несколько к записи, и один, указывающий на ошибки. Вы не обязательно должны иметь все три, это зависит от того, что делает ваш код.
После того, как вы настроили fdsets, вы передаете их вместе с числом fds и тайм-аутом на select
, который ткет свою магию и возвращается к вам. Перед этим сделайте копию (FD_COPY
) fdsets для последующего восстановления.
По возвращении произошла ошибка, тайм-аут или событие, относящееся к одному из интересующих элементов. В этом последнем случае fdsets были изменены, чтобы установить fds только для тех, у кого есть событие, и вы можете использовать FD_ISSET
, чтобы определить, какие из них.
Затем, как только вы обработаете все события, используйте FD_COPY
, чтобы восстановить исходные наборы fdsets (они были изменены с помощью select
, запомните) и снова вызовите select
. Продолжайте столько, сколько вам нужно.
Имейте в виду, что ошибка, возвращаемая из select
, не обязательно является фатальной. Вы можете получить (в errno
) EAGAIN
за временную нехватку ресурсов или EINTR
, если сигнал был обработан. Для этого второго случая вы можете просто повторно ввести вызов select. Во-первых, я бы реализовал цикл повторения в случае, если он был просто временным.