Мне просто нужно прочитать до N
байтов из SslStream
, но если ни один байт не был получен до истечения времени ожидания, отмените, оставив поток в допустимом состоянии, чтобы повторить попытку позже. (*)
Это можно легко сделать для потоков без SSL, т. е. NetworkStream
, просто используя его свойство ReadTimeout
, которое заставит поток генерировать исключение по тайм-ауту. К сожалению, этот подход не работает на SslStream
в официальных документах:
SslStream предполагает, что тайм-аут вместе с любым другим исключением IOException, когда оно выбрасывается из внутреннего потока, будет рассматриваться вызывающей стороной как фатальное. Повторное использование экземпляра 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
.