Мне просто нужно прочитать до N
байтов от SslStream
, но если байт не был получен до истечения таймаута, отмените его, оставив поток в допустимом состоянии, чтобы повторить попытку позже. (*)
Это можно легко сделать для потоков без SSL, т.е. NetworkStream
, просто используя его свойство ReadTimeout
, которое сделает поток генерирует исключение в таймаут. К сожалению, этот подход не работает на SslStream
в официальных документах:
SslStream предполагает, что тайм-аут вместе с любым другим исключением IO, когда он выкинут из внутреннего потока, будет считаться фатальным его вызывающим. Повторное использование экземпляра SslStream после таймаута возвращает мусор. Приложение должно закрыть SslStream и выбросить исключение в этих случаях.
[Обновлено 1] Я пробовал использовать другой подход:
task = stream->ReadAsync(buffer, 0, buffer->Length);
if (task->Wait(timeout_ms)) {
count = task->Result;
...
}
Но это не работает, если Wait()
возвращен false
: при вызове ReadAsync()
снова он выдает исключение:
Исключение выбрано: System.NotSupportedException в System.dll Tests.exe Предупреждение: 0: Ошибка чтения из сокета: System.NotSupportedException: метод BeginRead не может быть вызван при ожидании другой операции чтения.
[Обновить 2]. Я попытался использовать еще один подход для реализации тайм-аутов, вызвав Poll(timeout, ...READ)
в базовом сокете TcpClient
: если он возвращает true
, затем вызовите Read()
в SslStream
, или если он возвращает false
, тогда у нас есть тайм-аут. Это также не работает: поскольку SslStream
предположительно использует собственные внутренние промежуточные буферы, Poll()
может возвращать false
, даже если в SslStream
есть данные, которые нужно прочитать.
[Обновить 3]. Еще одна возможность - создать пользовательский подкласс Stream
, который будет находиться между NetworkStream
и SslStream
и захватить исключение тайм-аута и вернуть 0 байт вместо SslStream
. Я не уверен, как это сделать, и, что более важно, я понятия не имею, что возвращение 0 байтов, прочитанных в SslStream
, все равно не испортило бы его.
(*) Причина, по которой я пытаюсь это сделать, заключается в том, что чтение синхронно с тайм-аутом из небезопасного или защищенного сокета - это шаблон, который я уже использую в iOS, OS X, Linux и Android для некоторого креста -платформенный код. Он работает для небезопасных сокетов в .NET, поэтому единственным оставшимся случаем является SslStream
.