Вопрос по sockets, c, c++, linux, unix – Самый эффективный способ обработки клиентского соединения (программирование сокетов)

6

Для каждого отдельного учебника и примеров, которые я видел в Интернете для учебников по сокетам Linux / Unix, код на стороне сервера всегда включает в себя бесконечный цикл, который проверяет соединение клиента каждый раз. Пример:

http://www.thegeekstuff.com/2011/12/c-socket-programming/

http://tldp.org/LDP/LG/issue74/tougher.html#3.2

Есть ли более эффективный способ структурировать код на стороне сервера, чтобы он не включал бесконечный цикл, или кодировать бесконечный цикл таким образом, чтобы он занимал меньше системных ресурсов?

Большая часть (эффективная в любом случае, т.е. не включая create / terminate / join) многопоточный код записывается в виде бесконечных циклов с блокирующим вызовом где-то вверху. Не беспокойтесь об этом :) Martin James

Ваш Ответ

7   ответов
6

бесконечный цикл в этих примерах уже эффективен. призыв кaccept() это блокирующий вызов: функция не возвращается, пока клиент не подключится к серверу. выполнение кода для потока, который называетсяaccept() Функция остановлена и не требует никакой вычислительной мощности.

думать оaccept() как призыв кjoin() или как ожидание мьютекса / блокировки / семафора.

конечно, есть много других способов обработки входящего соединения, но эти другие способы связаны с блокирующим характеромaccept(), эту функцию трудно отменить, поэтому существуют неблокирующие альтернативы, которые позволят серверу выполнять другие действия во время ожидания входящего соединения. одна такая альтернатива используетselect(), другие альтернативы менее переносимы, так как включают низкоуровневые вызовы операционной системы для сигнализации о соединении через функцию обратного вызова, событие или любой другой асинхронный механизм, обрабатываемый операционной системой ...

Именно так. С точки зрения операционной системы (особенно для Linux), когда вы звонитеaccept() (блокирует вызов) в вашем процессе, и нет входящих соединений, ваш процесс переходит в спящий режим: его состояние изменяется с TASK_RUNNING на TASK_ (UN) INTERRUPTIBLE, и он подключается к одной из очередей ожидания ядра. Затем вызывается планировщик для выбора следующего запускаемого процесса, поэтому с точки зрения ОС время обработки не теряется. Ваш процесс будет разбужен, когда поступят новые запросы на подключение.
1

Бесконечный цикл предназначен для поддержания рабочего состояния сервера, поэтому, когда клиентское соединение принято, сервер сразу же не завершит работу, вместо этого он вернется к прослушиванию другого клиентского соединения.

Вызов listen () является блокирующим, то есть он ожидает получения данных. Это делает это чрезвычайно эффективным способом, используя нулевые системные ресурсы (конечно, до тех пор, пока не будет установлено соединение), используя сетевые драйверы операционных систем, которые запускают событие (или аппаратное прерывание), которое пробуждает поток прослушивания.

Второй абзац в основном неверный. listen () не ждет и не получает данные. accept () ожидает, но он также не получает данные, он получает соединения. Это делается не через аппаратные прерывания или сетевые драйверы, а через стек TCP / IP и очередь невыполненных работ.
0

В дополнение к тому, что уже было опубликовано, довольно легко увидеть, что происходит с отладчиком. Вы сможете выполнять пошаговое выполнение до тех пор, пока не выполните строку accept (), в которой "sigle-step" выделение исчезнет, и приложение будет запущено - следующая строка не достигнута. Если вы поставите контрольную точку на следующей строке, она не сработает, пока клиент не подключится.

1

Вот хороший обзор того, какие методы доступны -Проблема C10K.

0

Мы должны следовать передовой практике написания программ клиент-сервер. Лучшее руководство, которое я могу рекомендовать вам в это времяПроблема C10K , В этом случае мы должны следовать конкретным вещам. Мы можем использовать select, poll или epoll. У каждого есть свои преимущества и недостатки.

Если вы запускаете свой код с использованием последней версии ядра, я бы порекомендовал перейти на epoll. Нажмите, чтобы увидеть пример программы, чтобы понятьEpoll.

Если вы используете select, poll, epoll, то вы будете заблокированы до тех пор, пока не получите событие / триггер, чтобы ваш сервер не работал в бесконечном цикле, потребляя ваше системное время.

Исходя из моего личного опыта, я считаю, что epoll - лучший способ пойти дальше, поскольку я заметил, что порог моей серверной машины при наличии 80k подключения ACTIVE был намного меньше при сравнении, он будет выбирать и опрашивать. Средняя нагрузка моей серверной машины составляла всего 3,2 при 80k активного соединения :)

При тестировании с опросом я обнаружил, что средняя нагрузка на мой сервер возросла до 7,8 при достижении 30k активного клиентского подключения :(.

0

Когда вы реализуете сервер, который прослушивает, возможно, бесконечные соединения, у меня нет возможности обойти какие-то бесконечные циклы. Обычно это вообще не проблема, потому что когда ваш сокет не помечен как неблокирующий, вызовaccept() будет блокироваться, пока не появится новое соединение. Из-за этой блокировки системные ресурсы не теряются.

Другие библиотеки, которые предоставляют систему, основанную на событиях, в конечном итоге реализуются способом, описанным выше.

1

Для C ++ вы можете посмотреть вBoost.Asio, Вы также можете посмотреть, например,асинхронный ввод / вывод функции. Существует такжеSIGIO.

Конечно, даже при использовании этих асинхронных методов ваша основная программа все равно должна находиться в цикле, иначе программа завершится.

Похожие вопросы