如何(反复)从.NET SslStream中读取超时? [英] How to (repeatedly) read from .NET SslStream with a timeout?
问题描述
我只需要从SslStream
读取最多N
个字节,但是如果在超时之前没有收到任何字节,请取消操作,同时将流保持为有效状态,以便稍后重试. (*)
I just need to read up to N
bytes from a SslStream
but if no byte has been received before a timeout, cancel, while leaving the stream in a valid state in order to try again later. (*)
对于非SSL流,即NetworkStream
只需使用其ReadTimeout
属性即可轻松完成,这将使流在超时时引发异常.不幸的是,根据官方文档,此方法不适用于SslStream
:
This can be done easily for non-SSL streams i.e. NetworkStream
simply by using its ReadTimeout
property which will make the stream throw an exception on timeout. Unfortunately this approach doesn't work on SslStream
per the official docs:
SslStream假定从内部流中抛出一个超时以及任何其他IOException将被其调用方视为致命.超时后重用SslStream实例将返回垃圾.在这种情况下,应用程序应关闭SslStream并引发异常.
SslStream assumes that a timeout along with any other IOException when one is thrown from the inner stream will be treated as fatal by its caller. Reusing a SslStream instance after a timeout will return garbage. An application should Close the SslStream and throw an exception in these cases.
[更新1] ,我尝试了另一种类似的方法:
[Updated 1] I tried a different approach like this:
task = stream->ReadAsync(buffer, 0, buffer->Length);
if (task->Wait(timeout_ms)) {
count = task->Result;
...
}
但是,如果Wait()
返回false
,这将不起作用:稍后再次调用ReadAsync()
时,它将引发异常:
But this doesn't work if Wait()
returned false
: when calling ReadAsync()
again later it throws an exception:
引发的异常:System.dll中的"System.NotSupportedException" Tests.exe警告:0:无法从套接字读取:System.NotSupportedException:当另一个读取操作挂起时,无法调用BeginRead方法.
Exception thrown: 'System.NotSupportedException' in System.dll Tests.exe Warning: 0 : Failed reading from socket: System.NotSupportedException: The BeginRead method cannot be called when another read operation is pending.
[更新2] ,我尝试了另一种方法来实现超时,方法是在基础TcpClient
套接字上调用Poll(timeout, ...READ)
:如果返回true
,则在Read()
上调用Read()
c12>,或者如果它返回false
,则我们有一个超时.这也不起作用:因为SslStream
可能使用了自己的内部中间缓冲区,所以即使在SslStream
中有待读取的数据,Poll()
仍可以返回false
.
[Update 2] I tried yet another approach to implement timeouts by calling Poll(timeout, ...READ)
on the underlying TcpClient
socket: if it returns true
, then call Read()
on the SSlStream
, or if it returns false
then we have a timeout. This doesn't work either: because SslStream
presumably uses its own internal intermediary buffers, Poll()
can return false
even if there's data left to be read in the SslStream
.
[更新3] 另一种可能性是编写一个自定义的Stream
子类,该子类位于NetworkStream
和SslStream
之间,并捕获超时异常并返回0字节而不是SslStream
仍不会以某种方式破坏它.
[Update 3] Another possibility would be to write a custom Stream
subclass that would sit between NetworkStream
and SslStream
and capture the timeout exception and return 0 bytes instead to SslStream
. I'm not sure how to do this, and more importantly, I have no idea if returning a 0 bytes read to SslStream
would still not corrupt it somehow.
(*)我尝试执行此操作的原因是,从非安全或安全套接字同步读取并超时,这是我已经在iOS,OS X,Linux和Android上使用的模式平台代码.它适用于.NET中的非安全套接字,因此剩下的唯一情况是SslStream
.
(*) The reason I'm trying to do this is that reading synchronously with a timeout from a non-secure or secure socket is the pattern I'm already using on iOS, OS X, Linux and Android for some cross-platform code. It works for non-secure sockets in .NET so the only case remaining is SslStream
.
推荐答案
您当然可以使方法1起作用.您只需要跟踪任务并继续等待,而无需再次调用ReadAsync.因此,非常粗略:
You can certainly make approach #1 work. You simply need to keep track of the Task and continue waiting without calling ReadAsync again. So, very roughly:
private Task readTask; // class level variable
...
if (readTask == null) readTask = stream->ReadAsync(buffer, 0, buffer->Length);
if (task->Wait(timeout_ms)) {
try {
count = task->Result;
...
}
finally {
task = null;
}
}
需要充实一些内容,以便调用者可以看到尚未完成读取,但是摘要太小,无法给出具体建议.
Needs to be fleshed-out a bit so the caller can see that the read isn't completed yet but the snippet is too small to give concrete advice.
这篇关于如何(反复)从.NET SslStream中读取超时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!