C #: Как я могу завершить сокет, прежде чем Socket.BeginReceive перезвонит? - PullRequest
5 голосов
/ 17 декабря 2009

У меня есть сервер, который получает запросы на подключение от клиентов. Этот сервер использует асинхронный метод Socket.BeginReceive и Socket.EndReceive. Код очень похож на код, найденный здесь .

В моем случае после вызова Socket.BeginReceive мне нужен тайм-аут, такой, что если клиент удерживает соединение, но не передает никаких данных в течение фиксированного периода времени, мне нужно прервать соединение.

  • Как мне прекратить связь в этом сценарии?
  • Каков наилучший способ кодирования таймер

Ответы [ 4 ]

10 голосов
/ 17 декабря 2009

Просто вызовите метод сокета Close(). После этого метод обратного вызова будет работать довольно быстро, вы получите ObjectDisposedException при вызове метода EndReceive(). Будьте готовы поймать это исключение.

Возможно, вы не хотите блокировать поток, который вызвал BeginReceive, вам понадобится System.Threading.Timer или System.Timers.Timer для определения времени ожидания. Его обратный вызов должен вызывать Close(). Остерегайтесь неизбежного состояния гонки, которое это вызывает, обратный вызов таймера будет запущен, если ответ получен за микросекунду до истечения таймера. Вы закроете розетку, даже если получили хороший ответ. Следующий вызов к BeginReceive() немедленно прекратится.

7 голосов
/ 29 января 2013

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

Лучшее решение для отмены ожидающего Socket.BeginReceive вызова - Socket.Shutdown, а не Socket.Close. Таким образом, асинхронный обработчик вызывается «нормально», и вызов Socket.EndReceive возвращает 0 -> вместо того, чтобы выдавать уродливое ожидаемое исключение. Вы всегда должны иметь

if (Socket.EndReceive() > 0) {
  //Do something
} else {
  //Socket has been shut down (either by you or the other end of the connection)
  //Now it's "safe" to call Socket.Close
  Socket.Close();
}

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

0 голосов
/ 17 декабря 2009

Вы можете получать некоторые исходные данные асинхронно, а затем выполнять синхронный прием для остальных данных и полагаться на ReceiveTimeout для отключения клиента. Вы можете использовать Socket.Close для принудительного отключения клиента.

Но если вы хотите использовать только асинхронный прием, вы можете использовать таймеры и сбросить их в EndReceive. Если это произойдет, вы можете принудительно отключить клиента.

Но я думаю, что первый подход лучше.

0 голосов
/ 17 декабря 2009

Согласно статье MSDN о Socket.BeginReceive говорится:

Чтобы отменить ожидающий BeginReceive, вызовите метод Close.

...