Исходные значения BeginReceive/BeginRead
Я использую NetworkStream и TcpClient для асинхронного приема данных с помощью BeginRead. Мне нужно применить тайм-аут к этой операции, так что через определенное время считывание будет прервано.
Насколько я могу сказать, это не поддерживается в NetworkStream или TcpClient - есть свойство ReceiveTimeout, но похоже, что это относится только к синхронному эквиваленту - "Читать".
Даже базовый класс Socket не поддерживает таймауты в методе BeginReceive.
Я искал эту проблему, и единственная предлагаемая резолюция, которую я видел, - это установить еще один фоновый поток, чтобы отменить операцию, если она не завершилась в течение периода ожидания. Это кажется ужасным взломом. Наверняка есть лучший способ?
Ответы
Ответ 1
Это единственный способ сделать это, потому что, когда вы используете асинхронную операцию, поток, инициировавший операцию, отключает выполнение чего-то другого. Тайм-аут доступен с синхронной версией, поскольку поток выполнения блокируется до тех пор, пока операция чтения не завершится.
Если вам придется использовать фоновый поток для отмены операции, тем не менее не будет смысла продолжать использовать асинхронные методы Begin/End. Если вы собираетесь отделить фоновый поток, просто выполните синхронную операцию чтения из фонового потока, а затем вы можете использовать ReceiveTimeout.
Ответ 2
Подождите 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);
Внутри обратного вызова Inside BeginReceive используйте
private void ReceiveCallBack(IAsyncResult ar)
{
/** Use ar to check if receive is correct and complete */
receiveDone.Set();
}