Может ли один сокет обрабатывать несколько одновременных запросов?

Обновлено: мое приложение многопоточное

Представьте, что у меня есть сервер,

int main()
{
   resolveAddrandPort(hostname, port); // Custom function
   
   SOCKET listening_socket = socket(/* args... */);   // Creates a socket.
   bind(listening_socket, /* args... */);             // Binds the socket to the address and port provided above.

   listen(listening_socket, default_backlog);         // Places the socket in a mode where it can accept any requests.

   add_handlers(10); // Custom function that adds 10 handlers which each run on different threads and can handle requests concurrently (using the same socket[=listening_socket]).

   while(is_recieving_requests)
   {
       SOCKET client_socket = accept(listening_socket, /* args... */);
       handle_request( // Custom function
            find_available_handler(), // Custom function that finds among the 10 handlers which of them is currently free and not handling any requests to handle this request.
            client_socket
       ); 

       clean_up(); // Custom function that cleans up after finishing with the request.
   }

   server_clean_up(); // Cleans up after the server.
}

Я использую winsock для создания сервера,

В документации о listen говорится, что вы можете указать отставание, определяющее, сколько запросов может находиться в ожидании.

Это может быть глупо, но я предполагаю, что один сокет не может одновременно обрабатывать несколько запросов. Если это так, я думаю, что мне нужно создать несколько listening_socket, чтобы иметь возможность обрабатывать это одновременно.

Пожалуйста, поправьте меня, если я ошибаюсь, и я благодарю вас за ваше терпение.

Вы можете обрабатывать несколько запросов с помощью одного сокета. Подумайте о UDP в качестве примера. Вы просто прослушиваете один сокет из любого случайного запроса.

Irelia 15.04.2023 20:51

Также в TCP вы используете один прослушивающий сокет для приема входящих соединений, которому затем вы можете назначить отдельный сокет для различения каждого соединения.

Irelia 15.04.2023 20:52

Я тоже не уверен в этом single socket cannot concurrently handle multiple request Что ты имеешь в виду под одновременно? Вроде одновременно? В однопоточном приложении это было бы невозможно в любом случае.

Irelia 15.04.2023 20:53

@Irelia Мое приложение многопоточное. И да одновременно

Amrit Sanjeev 15.04.2023 20:56

Почему он многопоточный?

Irelia 15.04.2023 20:57

@Irelia Server IO будет более эффективным

Amrit Sanjeev 15.04.2023 20:57

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

Irelia 15.04.2023 20:59

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

Amrit Sanjeev 15.04.2023 21:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
106
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

один сокет не может одновременно обрабатывать несколько запросов

Одновременно это то, что сбивает меня с толку. Отставание подразумевает, что у вас может быть x максимальное количество ожидающих запросов, пока вы их не примете или не отклоните, после чего будут разрешены новые запросы.

В TCP для приема запросов от подключений будет использоваться один сокет прослушивания. Затем вы можете различать каждое соединение с его собственным сокетом.

В UDP один сокет прослушивания может использоваться для приема запросов, которые определяются их удаленным адресом. Вы также можете отправлять сообщения на множество разных соединений, используя этот удаленный адрес с одним сокетом.

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

Если вы думаете о запуске потока для каждого сокета, чтобы вы могли прочитать запрос от каждого из них (что делают многие новички в сети, потому что они откуда-то узнали). И, судя по вашему коду, это похоже на то, что вы делаете. ЭТО УЖАСНАЯ ИДЕЯ! Это может быть «правильным» решением для эфемерных сокетов (одиночных HTTP-запросов), но не для долгосрочных соединений. Но я бы даже не стал использовать поток на сокет даже для одного запроса. Это может привести к уязвимостям.

Вам не нужно несколько прослушивающих сокетов. Один работает нормально.

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

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

Это все о TCP. UDP работает немного иначе, здесь нет соединений, только сообщения.

Вам не нужно несколько прослушивающих сокетов, и на самом деле у вас не может быть нескольких прослушивающих сокетов TCP.

У вас есть один разъем для прослушивания. Этот сокет используется для приема соединений, и каждому из этих соединений назначается собственный сокет.

У вас может быть один поток, который прослушивает новые соединения, а затем, когда он его получает, он может передать принятый сокет либо новому потоку, либо существующему потоку в пуле. Таким образом, у вас есть один поток, который просто прослушивает новые соединения, и несколько других потоков, каждый из которых обрабатывает активное соединение. Это будет иметь ограничения, например, если у вас больше потоков, чем ядер ЦП, тогда некоторые будут ожидать других, но это будет работать.

Другие вопросы по теме