Обновлено: мое приложение многопоточное
Представьте, что у меня есть сервер,
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
, чтобы иметь возможность обрабатывать это одновременно.
Пожалуйста, поправьте меня, если я ошибаюсь, и я благодарю вас за ваше терпение.
Также в TCP вы используете один прослушивающий сокет для приема входящих соединений, которому затем вы можете назначить отдельный сокет для различения каждого соединения.
Я тоже не уверен в этом single socket cannot concurrently handle multiple request
Что ты имеешь в виду под одновременно? Вроде одновременно? В однопоточном приложении это было бы невозможно в любом случае.
@Irelia Мое приложение многопоточное. И да одновременно
Почему он многопоточный?
@Irelia Server IO будет более эффективным
Это не обязательно так. Вы можете запускать очень эффективные серверы в одном потоке. Большинство людей, использующих многопоточные серверы, на самом деле не понимают, зачем они это делают.
Я имею в виду, что вы можете, но гораздо проще просто делегировать эту работу другим потокам. И многопоточность была сделана для таких ситуаций
Ваш вопрос немного расплывчатый, но я попытаюсь обобщить. У вас может быть один сокет прослушивания для приема запросов от входящих соединений или сообщений (относительно UDP).
один сокет не может одновременно обрабатывать несколько запросов
Одновременно это то, что сбивает меня с толку. Отставание подразумевает, что у вас может быть x максимальное количество ожидающих запросов, пока вы их не примете или не отклоните, после чего будут разрешены новые запросы.
В TCP для приема запросов от подключений будет использоваться один сокет прослушивания. Затем вы можете различать каждое соединение с его собственным сокетом.
В UDP один сокет прослушивания может использоваться для приема запросов, которые определяются их удаленным адресом. Вы также можете отправлять сообщения на множество разных соединений, используя этот удаленный адрес с одним сокетом.
Я думаю, что двусмысленность в вашем вопросе заключается в том, можете ли вы читать запросы из многих сокетов одновременно в одном потоке. В типичном блокирующем вводе-выводе вы можете читать только из одного сокета за раз. Вот почему существуют неблокирующие сокеты. Это может позволить вам пройтись по каждому сокету и проверить, есть ли ожидающие данные. В этом случае данные можно восстановить.
Если вы думаете о запуске потока для каждого сокета, чтобы вы могли прочитать запрос от каждого из них (что делают многие новички в сети, потому что они откуда-то узнали). И, судя по вашему коду, это похоже на то, что вы делаете. ЭТО УЖАСНАЯ ИДЕЯ! Это может быть «правильным» решением для эфемерных сокетов (одиночных HTTP-запросов), но не для долгосрочных соединений. Но я бы даже не стал использовать поток на сокет даже для одного запроса. Это может привести к уязвимостям.
Вам не нужно несколько прослушивающих сокетов. Один работает нормально.
Когда приходит запрос на соединение, создается новое соединение, accept
возвращает новый сокет, созданный специально для этого соединения, и вы продолжаете обслуживать это соединение из этого сокета. Тем временем прослушивающий сокет готов принять новое соединение.
У вас не может быть много запросов на соединение одновременно, потому что одно физическое соединение (Ethernet или что-то еще) передает один пакет за раз. Бэклог нужен, когда запросы приходят быстрее, чем вы можете их accept
(по-прежнему по одному). На многопоточном сервере это в основном не проблема. accept
выполняется практически мгновенно, вы отправляете полученный сокет рабочему потоку для обслуживания, а затем прослушивающий поток снова готов accept
.
Это все о TCP. UDP работает немного иначе, здесь нет соединений, только сообщения.
Вам не нужно несколько прослушивающих сокетов, и на самом деле у вас не может быть нескольких прослушивающих сокетов TCP.
У вас есть один разъем для прослушивания. Этот сокет используется для приема соединений, и каждому из этих соединений назначается собственный сокет.
У вас может быть один поток, который прослушивает новые соединения, а затем, когда он его получает, он может передать принятый сокет либо новому потоку, либо существующему потоку в пуле. Таким образом, у вас есть один поток, который просто прослушивает новые соединения, и несколько других потоков, каждый из которых обрабатывает активное соединение. Это будет иметь ограничения, например, если у вас больше потоков, чем ядер ЦП, тогда некоторые будут ожидать других, но это будет работать.
Вы можете обрабатывать несколько запросов с помощью одного сокета. Подумайте о UDP в качестве примера. Вы просто прослушиваете один сокет из любого случайного запроса.