Начать принимать новые соединения до или после EndAccept()

У меня есть вопрос о том, в какой момент после BeginAccept в сокете я могу сообщить моему потоку прослушивателя, что он может снова начать принимать соединения.

Это код, который у меня есть:

while(!mStopWaitHandle.WaitOne(0, false)) // <-- Manual Reset event to check if the service has stopped.
{
    Logging.Debug("Waiting for a connection...");

    socket.BeginAccept(new AsyncCallback(AcceptConnection), socket);

    mReadyToAcceptWaitHandle.WaitOne(); // <-- AutoResetEvent to block until I can continue accepting connections
}

затем в моем асинхронном обратном вызове:

private void AcceptConnection(IAsyncResult ar)
{
    mReadyToAcceptWaitHandle.Set(); // <-- Tell the listener thread to start accepting connections again

    Socket socket = (Socket)ar.AsyncState;
    Socket workerSocket = socket.EndAccept(ar);

    ... handle connection on workerSocket ...
}

Вот как они это делают в асинхронном сокете сервера Пример на msdn.

Но из того, что я прочитал, BeginAccept не является блокирующим вызовом. Блокирующий вызов — EndAccept, и он блокируется до тех пор, пока не появится соединение для принятия.

Таким образом, наличие mReadyToAcceptWaitHandle.Set();, чтобы сообщить потоку прослушивателя продолжать принимать соединения, до того, как EndAccept() кажется мне странным, потому что разве это не приведет к тому, что он просто продолжит открывать потоки обработчика AcceptConnection (из того, что я видел при выполнении, это не кажется, не делают этого, но я не знаю, почему?), что все просто блокируется на EndAccept?

Не лучше ли было бы иметь mReadyToAcceptWaitHandle.Set(); после EndAccept, чтобы он имел дело только с приемом одного соединения за раз, и после того, как он принят, но до того, как он фактически обработает связь по соединению.

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

Что мне здесь не хватает?

Заранее спасибо.


person Tom Heard    schedule 22.06.2014    source источник


Ответы (1)


The blocking call is EndAccept, and it blocks until there is a connection to accept.

Это не точное описание.

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

Таким образом, на самом деле нет необходимости использовать события для синхронизации, когда принимать новые соединения. Просто снова вызовите BeginAccept из обратного вызова.

person 500 - Internal Server Error    schedule 22.06.2014
comment
Согласно разделу примечаний msdn.microsoft.com /en-us/library/chfa7866(v=vs.110).aspx, документации EndAccept, EndAccept действительно блокируется до тех пор, пока в очереди входящих подключений не появится соединение для принятия. В любом случае вызов BeginAccept из обратного вызова BeginAccept ничем не отличается от вызова его из того же места, что и исходный BeginAccept, после ожидания сигнала на WaitHandle, как я делаю в своем коде. На самом деле, по-моему, это чище и позволяет мне больше проверять другие состояния, такие как остановка службы. На самом деле мой способ таков, как они это делают в примере MSDN. - person Tom Heard; 23.06.2014
comment
К тому же вы даже не ответили на мой вопрос. - person Tom Heard; 23.06.2014
comment
Хотя он блокируется, он делает это только на мгновение, потому что обратный вызов вызывается только тогда, когда действительно есть соединение, которое нужно принять. - person 500 - Internal Server Error; 23.06.2014
comment
Вы сами в комментариях stackoverflow.com/a/15557881/2709382 сказали, что BeginAccept не блокирует. - person Tom Heard; 23.06.2014
comment
OHHH, AsyncCallback выполняется только тогда, когда есть соединение для принятия, но BeginAccept не блокируется. - person Tom Heard; 23.06.2014
comment
В том посте я говорил о BeginAccept, а не о EndAccept. - person 500 - Internal Server Error; 23.06.2014
comment
О, мой плохой. Можете ли вы указать это в своем ответе, и я соглашусь. - person Tom Heard; 23.06.2014
comment
Я также верну свой отрицательный голос, но смогу сделать это только после того, как вы отредактируете. Извините, я не видел, как ваш первоначальный ответ отвечал на мой вопрос. - person Tom Heard; 23.06.2014
comment
Давайте продолжим это обсуждение в чате. - person Tom Heard; 23.06.2014
comment
Почему бы не использовать асинхронный API на основе задач и вообще не заморачиваться с парами начала и конца APM? Я считаю их фактически устаревшими... Использование их сейчас является формой мазохизма. - person spender; 23.06.2014