#c #sockets #select #asynchronous
#c #сокеты #выберите #асинхронный
Вопрос:
Я хочу написать асинхронный сервер сокетов на C, но прежде чем я это сделаю, я проведу некоторое исследование. Рассмотрим пример сокета select(), показанный здесь: http://www.gnu.org/s/hello/manual/libc/Server-Example.html#Server-Example Я вижу, что примерная программа будет принимать только одного клиента для каждого цикла выбора (если я правильно читаю). Итак, если есть 20 клиентов и еще два пытаются подключиться, примет ли он только 21-го клиента, затем обработает остальные 20 (в худшем случае, предполагая, что все остальные 20 требуют чтения), а ЗАТЕМ примет 22-й? Было бы лучше, если бы я прервал цикл после принятия клиента, чтобы он мог снова выбрать () и позаботиться обо всех ожидающих клиентах перед обработкой подключенных? Или это противоречит цели использования select()? Спасибо.
Ответ №1:
Шаблон сервера, показанный в примере, на который вы ссылались, в порядке; нет никаких существенных проблем, связанных с тем, что цикл принимает только один сокет на итерацию.
Ключевой момент, который следует иметь в виду, заключается в том, что в хорошо продуманном цикле select() единственное место, которое процесс должен блокировать, находится внутри вызова select() . В частности, при правильном кодировании сервер никогда не заблокирует внутри send() , recv() или accept() . Лучше всего установить все сокеты в неблокирующий режим (через fcntl(fd, F_SETFL, O_NONBLOCK)), чтобы гарантировать такое поведение.
Учитывая это, точный порядок «какие клиенты обслуживаются первыми в любой конкретной итерации цикла событий» не имеет значения, потому что все сокеты клиентов обрабатываются очень скоро после того, как у них есть данные, готовые к чтению (или буферное пространство, готовое к записи), и все новые соединения принимаются быстро.
Комментарии:
1. Конечно, вы могли бы ограничить объем данных, которые вы отправляете / получаете на каждой итерации, чтобы избежать длинных запросов, останавливающих более короткие. Я думаю, что веб-сервер Zeus сделал что-то в этом роде. Вероятно, вам следует также добавить некоторую случайность в отношении того, какие запросы вы обрабатываете в первую очередь.
2. Спасибо, я думал, что смогу исправить ошибку в своей программе, прервав работу после принятия клиента, но это фактически снизило бы производительность. Думаю, я не могу выбрать простой выход.
Ответ №2:
select() оставляет программисту решать, как обрабатывать уведомления. Один вызов select() может указывать на то, что у любого или всех сокетов есть байты для чтения и некоторые запросы на подключение для обработки. Приложение может обработать все уведомления перед вызовом select() или обработать одно уведомление перед повторным вызовом select() .
Ответ №3:
Вы можете использовать poll() в прослушивающем сокете после accept(), чтобы узнать, есть ли еще клиенты, ожидающие подключения.
Обратите внимание, что количество одновременных попыток подключения обрабатывается параметром backlog для прослушивания (server_sock, backlog) — backlog равен 1 в примере, на который вы ссылаетесь.