如何(反复)从.NET SslStream中读取超时? [英] How to (repeatedly) read from .NET SslStream with a timeout?

查看:269
本文介绍了如何(反复)从.NET SslStream中读取超时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只需要从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子类,该子类位于NetworkStreamSslStream之间,并捕获超时异常并返回0字节而不是.我不确定如何执行此操作,更重要的是,我不知道是否将读取到的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆