Тайм-ауты BeginReceive / BeginRead

Я использую NetworkStream и TcpClient для асинхронного получения данных с помощью BeginRead. Мне нужно применить тайм-аут к этой операции, чтобы по истечении указанного времени чтение было прервано.

Насколько я могу судить, это не поддерживается в NetworkStream или TcpClient — есть свойство ReceiveTimeout, но оно, по-видимому, применимо только к синхронному эквиваленту — «Чтение».

Даже базовый класс Socket не поддерживает тайм-ауты в методе BeginReceive.

Я искал эту проблему, и единственное предлагаемое решение, которое я видел, - это настроить другой фоновый поток для отмены операции, если она не завершается в течение периода ожидания. Это похоже на ужасный взлом. Наверняка есть лучший способ?


person Barg    schedule 12.08.2010    source источник


Ответы (2)


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

Однако если вам придется использовать фоновый поток для отмены операции, не будет особого смысла продолжать использовать асинхронные методы Begin/End. Если вы собираетесь выделить фоновый поток, просто выполните синхронную операцию чтения из фонового потока, а затем вы можете использовать метод ReceiveTimeout.

person Joel C    schedule 21.04.2011
comment
Джоэл указывает нам правильное направление в отношении неиспользования фонового потока для отмены, но, если это не очевидно, многие люди используют 1 поток (возможно, из рабочего опроса), который периодически очищает мертвые соединения. Это необходимо для освобождения дескрипторов сокетов/и т. д., и особенно важно, если вы когда-нибудь столкнетесь с чем-то вроде атаки типа «отказ в обслуживании» — преднамеренной или нет. - person eselk; 22.05.2012
comment
Другой вариант — System.Threading.Timer, который не взяться за нить. - person hangar; 29.12.2014
comment
@hangar Существует 4 реализации Timer, System.Threading.Timer действительно занимает поток, он просто запускается в пуле потоков, поэтому вам не нужно вручную управлять ресурсами, необходимыми для функции таймера. docs.microsoft.com/en- нас/dotnet/api/ - person Kieran Devlin; 12.08.2020

Подождите ManualResetEvent с некоторым значением времени ожидания, чтобы сигнализировать, когда задача завершена. Если время ожидания истекло до того, как будет передан сигнал, вы знаете, что асинхронная операция никогда не завершалась.

private ManualResetEvent receiveDone = new ManualResetEvent(false);

receiveDone.Reset();
socket.BeginReceive(...);
if(!receiveDone.WaitOne(new TimeSpan(0, 0, 0, 30))) //wait for 30 sec.
    throw new SocketException((int)SocketError.TimedOut);

Внутри обратного вызова BeginReceive используйте

private void ReceiveCallBack(IAsyncResult ar)
{
    /** Use ar to check if receive is correct and complete */
    receiveDone.Set();
}
person vivek.m    schedule 12.07.2012
comment
Голосование против, потому что это именно то, что я (наивно) сделал, и это не работает. Каждый вызов BeginReceive, который не соответствует вызову EndReceive, приведет к утечке ресурсов ядра. Отобразите активность процесса в чем-то вроде Perfmon и наблюдайте за медленной утечкой невыгружаемого пула. Если это длится достаточно долго (в моем случае, часы), вы в конечном итоге получите исключение с кодом ошибки WSAENOBUFS; Не удалось выполнить операцию над сокетом, поскольку в системе не хватило места в буфере или из-за того, что очередь была заполнена. - person Anthony; 16.10.2013
comment
Я не проверял это, но можем ли мы решить вашу проблему, вызвав socket.EndReceive(..) перед тем, как выдать исключение? IAsyncResult, необходимый для вызова EndReceive, возвращается функцией BeginReceive. Голосование за ваш комментарий. Спасибо за обновления. - person vivek.m; 18.10.2013
comment
так что... в конце концов, это не та асинхронная операция. я имею в виду, какой смысл использовать BeginReceive, если вы блокируете поток до истечения времени ожидания? вместо этого просто используйте синхронные операции с тайм-аутами сокетов. - person RoeeK; 24.11.2014