Есть ли лучший способ использовать асинхронные TCP-сокеты в C ++ вместо опроса или выбора?

Недавно я начал писать код на C ++, использующий сокеты, который я хотел бы использовать асинхронно. Я читал много постов о том, как poll и select могут использоваться для асинхронности моих сокетов (используя poll или select, чтобы ждать буфер send или recv), но на моей стороне сервера у меня есть массив struct pollfd, где каждый раз прослушивающий сокет принимает соединение, он добавляет его в массив struct pollfd, чтобы он мог отслеживать recv (POLLIN) этого сокета.

Моя проблема в том, что если у меня есть 5000 сокетов, подключенных к моему сокету прослушивания на моем сервере, то массив struct pollfd будет иметь размер 5000, поскольку он будет контролировать все подключенные сокеты, НО единственный способ, которым я знаю, как проверить, готово ли recv для сокета, путем обхода всех элементов в массиве struct pollfd, чтобы найти те, чьи обеты равны POLLIN. Это просто кажется неэффективным, когда количество подключенных розеток очень велико. Есть ли лучший способ сделать это?

Как библиотека boost :: asio обрабатывает async_accept, async_send и т. д ...? Как мне справиться с этим?

7 голосов | спросил Aadesh P 6 Jam1000000amWed, 06 Jan 2016 02:25:02 +030016 2016, 02:25:02

1 ответ


0

Какого черта, я пойду вперед и напишу ответ.

Я собираюсь игнорировать термины "асинхронный" и "неблокирующий", потому что я считаю, что это не имеет отношения к вашему вопросу.

Вы беспокоитесь о производительности при работе с тысячами сетевых клиентов, и вы правы. Вы вновь обнаружили проблему C10K . Когда Интернет был молодым, люди видели необходимость в небольшом количестве быстрых серверов для обслуживания большого количества (относительно) медленных клиентов. Существующие интерфейсы типа select /poll требуют линейного сканирования - как в ядре, так и в пространстве пользователя - по всем сокетам, чтобы определить, какие из них готовы. Если многие сокеты часто простаивают, ваш сервер может потратить больше времени на выяснение того, что делать, чем на фактическую работу.

Перенесемся в будущее, где у нас есть два основных подхода к решению этой проблемы:

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

2) Используйте один из специфичных для платформы интерфейсов, которые были представлены для решения проблемы C10K. Это означает epoll (Linux), kqueue (BSD /Mac) или порты завершения (Windows). (Если вы считаете, что epoll совпадает с poll, посмотрите еще раз.) Все они будут только уведомлять ваше приложение о сокетах, которые действительно готовы, избегая расточительного линейного сканирования через незанятые соединения. Существует несколько библиотек, облегчающих использование этих платформно-ориентированных интерфейсов, включая libevent, libev и Boost.Asio. Вы обнаружите, что все они в конечном итоге вызывают epoll в Linux, kqueue в BSD и т. Д., Когда такие интерфейсы доступны.

ответил Nemo 6 Jpm1000000pmWed, 06 Jan 2016 20:57:35 +030016 2016, 20:57:35

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132