[Обновление 2014]: Кажется, что пример был изменен с момента публикации этого ответа, как отмечалось в этой теме . Пример MSDN теперь правильно обрабатывает несколько входящих подключений. В любом случае, общий подход, описанный здесь, является правильным и, возможно, он может дать дополнительные разъяснения.
При работе с сокетами у вас обычно есть один слушатель сокет для всех входящих соединений и несколько обработчиков сокетов для каждого подключенного клиента.
Прослушивание входящих соединений
Когда вы начинаете прослушивать порт, вы создаете сокет с методом обратного вызова для входящих соединений (это ссылка на пример , который вы упомянули). Это единственное гнездо слушателя для этого номера порта:
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
Эта строка указывает слушателю вызывать метод AcceptCallback
всякий раз, когда подключается новый клиент ( обратный вызов нового соединения ). Этот метод должен выполнять свою работу быстро, так как он блокирует другие входящие соединения.
Создание выделенных сокетов обработчиков
Именно поэтому AcceptCallback
должен немедленно создать выделенный "обработчик" сокета со своим собственным фоном обратный вызов данных метод (ReadCallback
):
// 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
вызывается только один раз). Чтобы разрешить несколько одновременных подключений, необходимо создать приемный сокет, используя handler.BeginReceive
, а затем вызвать listener.BeginAccept
, чтобы начать прослушивание новых клиентов.