Механизм прерываний в C, C ++ - PullRequest
1 голос
/ 26 мая 2010

Привет, я писал клиентский сервер udp, на котором клиент ожидает пакеты от сервера. Но я хочу ограничить это ожидание определенным временем. После того, как клиент не получит ответ в течение определенного момента, вызовите тревогу, в основном это выходит и начинает предпринимать шаги по исправлению. Итак, каковы возможные решения для этого. Я думаю, что написание обертки вокруг recv будет работать, но как именно это должно быть сделано, я имею в виду, как заставит recv поднять тревогу для вас после этого срока.

Любая помощь в этом отношении будет оценена.

Спасибо!

Ответы [ 2 ]

6 голосов
/ 26 мая 2010

Если вы хотите установить сокетную связь с тайм-аутами, тогда вам нужно использовать 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. Во-первых, я бы реализовал цикл повторения в случае, если он был просто временным.

1 голос
/ 26 мая 2010

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

Вы также можете использовать сигналы, но они не переносимы, и даже в системах, где они есть, они могут работать не так, как вы ожидаете по умолчанию. (Recv / select / независимо от того, что может быть перезапущено после того, как обработчик сигнала закончил, победив всю цель.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...