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

Как прервать сокет BeginReceive()?

Естественно, BeginReceive() никогда не закончится, если нет данных. MSDN предлагает, что вызов Close() отменяет BeginReceive().

Однако вызов Close() в сокете также выполняет на нем Dispose(), как это было показано в этом замечательном ansewr, и, следовательно, EndReceive() будет бросать исключение, потому что объект уже расположен (и он делает!).

Как мне следует продолжить?

4b9b3361

Ответ 1

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

MSDN действительно об этом умалчивает, но если вы посмотрите на документацию другого метода асинхронного сокета, BeginConnect(), вот что мы находим

Отменить ожидающий вызов на BeginConnect(), закройте Разъем. Когда метод Close() называется асинхронной операцией выполняется, обратный вызов предоставляется к методу BeginConnect() является называется. Последующий вызов Метод EndConnect (IAsyncResult) будет выбросить ObjectDisposedException в указывают, что операция была отменен.

Если это правильный способ для BeginConnect, это, вероятно, так и для BeginReceive. Это, безусловно, плохой дизайн со стороны API асинхронизации Microsoft, поскольку заставить пользователя обязательно исключать бросок и исключение, как часть обычного потока, будет раздражать отладчик. У вас действительно нет возможности "подождать", пока операция не будет завершена, потому что Close() - это то, что завершает ее в первую очередь.

Ответ 2

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

После того, как стек имеет операцию отправки или получения, он связан параметрами сокета сокета.

Используйте небольшой тайм-аут отправки или получения и используйте его перед операцией, поэтому вам все равно, изменилось ли оно во время той же операции на что-то более короткое или длинное.

Это приведет к большему переключению контекста, но не требует закрытия сокета под любым протоколом.

Например:

1) Установите небольшой тайм-аут

2) Выполнять операции

3) Установите таймаут больше

Это похоже на использование Blocking = false, но с автоматическим таймаутом, который вы укажете.

Ответ 4

Для соединений сокетов TCP вы можете использовать свойство Connected, чтобы определить состояние сокета, прежде чем пытаться получить доступ к любым утилитам, В MSDN:

"Свойство Connected получает состояние соединения Socket от последней операции ввода-вывода. Когда он возвращает false, Socket был либо никогда не подключен, либо больше не подключен."

Так как он говорит, что "больше не подключен", это означает, что ранее был вызван Close() в сокете. Если вы проверяете, подключен ли сокет в начале обратного вызова приема, исключений не будет.

Ответ 5

Другим решением было бы отправить "себе" "управляющее сообщение", используя сокет, связанный с другим портом. Это не совсем прервал, но это закончило бы операцию async.

Ответ 6

Я тоже боролся с этим, но, насколько я могу судить, используя простой логический флаг перед вызовом .BeginReceive(), он будет работать (так что не будет необходимости в обработке исключений). Поскольку у меня уже была обработка начала/остановки, это исправление было одним из операторов if (прокрутите вниз до нижней части метода OnReceive()).

if (_running)
{
    _mainSocket.BeginReceive(_data, 0, _data.Length, SocketFlags.None, OnReceive, null);
}                

Должен ли я пропустить что-то с этим подходом, дайте мне знать!