Подтвердить что ты не робот

Несколько клиентов асинхронного сервера

Я работал со следующим кодом, опубликованным в msdn:

http://msdn.microsoft.com/en-us/library/fx6588te.aspx

Я понимаю, что серверное приложение не заблокировано, пока приложение ожидает новых клиентов.

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

  • Что произойдет, если клиент A и B будут подключены одновременно?

  • Если клиент A подключается, и обработка его запроса занимает 5 секунд, если клиент B подключается через секунду, он должен дождаться завершения действия клиента A до того, как его обработка начнется?

  • Или клиентские запросы A и клиента B будут обрабатываться одновременно?

Я провел некоторое тестирование с этим, поставив команды Thread.Sleep(n) между данными приема/отправки в коде слушателя сокета. Затем я могу отправить несколько запросов в сокет, и они, похоже, будут обработаны. Однако сокет всегда обрабатывает их по одному и тому же идентификатору потока, что заставляет меня поверить, что он фактически не происходит одновременно.

Особенно учитывая описание microsoft, которое это приложение просто не блокирует, ожидая новых соединений - означает ли это, что он может обрабатывать параллельные соединения?

4b9b3361

Ответ 1

[Обновление 2014]: Кажется, что этот пример был изменен, поскольку этот ответ был опубликован, как отмечено в этом потоке. Пример MSDN теперь обрабатывает несколько входящих соединений должным образом. Во всяком случае, общий подход, описанный здесь, является правильным и, возможно, может дать дополнительное разъяснение.


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

Прослушивание входящих соединений

Когда вы начинаете слушать порт, вы создаете сокет с методом обратного вызова для входящих соединений (это ссылается на пример, который вы упомянули). То, что для этого номера порта используется <единственный > список прослушивателя:

listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

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

Создание выделенных сокетов-обработчиков

Вот почему AcceptCallback должен немедленно создать выделенный "обработчик" с помощью собственного метода обработки данных:

// inside AcceptCallback, we switch to the handler socket for communication
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
    new AsyncCallback(ReadCallback), state); // fired on a background thread

С этого момента метод ReadCallback вызывается всякий раз, когда ваш новый клиент получает ваш запрос.

Кроме того, перед возвратом AcceptCallback необходимо снова вызвать listener.BeginAccept, чтобы продолжить прослушивание новых входящих соединений:

// this is the same server socket we opened previously, which will now 
// continue waiting for other client connections: it doesn't care about
// the actual data transmission between individual clients
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

Эта часть не указана в примере MSDN, что означает, что она может принимать только одно соединение.

Получение данных

Как только вы получите пакет данных от вашего клиента, будет вызван метод ReadCallback. Таким образом, внутри этого метода обратного вызова данных вам необходимо прочитать и обработать полученные данные, а затем снова вызвать тот же метод BeginReceive (опять же, с помощью ReadCallback в качестве метода обратного вызова данных).

[изменить]

Проблема с примером MSDN заключается в том, что он позволяет подключать только одного клиента (listener.BeginAccept вызывается только один раз). Чтобы разрешить параллельные соединения mulitple, вам необходимо создать приемный сокет с помощью handler.BeginReceive, а затем вызвать listener.BeginAccept, чтобы начать прослушивание новых клиентов.

Ответ 2

Каждый сокет будет иметь связанную с ним очередь прослушивания. Это будет иметь ожидающие/частично принятые входящие соединения. Максимальное количество ожидающих подключений может быть определено программным способом в API-интерфейсе listen(), который является ничем иным, как "listener.Listen(100)" в этом примере. Имея это значение 100 здесь, "слушатель" сокета может иметь 150 (= 2 * 100/2) ожидающих соединений в очереди на прослушивание.