C# 中是否有 System.IO.BufferedStream 的替代方案?
-
23-08-2019 - |
题
我收到以下异常:
System.NotSupportedException : This stream does not support seek operations.
at System.Net.Sockets.NetworkStream.Seek(Int64 offset, SeekOrigin origin)
at System.IO.BufferedStream.FlushRead()
at System.IO.BufferedStream.WriteByte(Byte value)
以下链接显示这是微软的一个已知问题。http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=273186
这个堆栈跟踪显示了两件事:
- System.IO.BufferedStream 做了一些荒谬的指针移动操作。BufferedStream 应该缓冲底层流而不是更多。如果有这样的寻道操作,缓冲区的质量就会很差。
- 对于不支持 Seek 的流,它永远无法稳定工作。
还有其他选择吗?我是否需要一个缓冲区和 C# 中的 NetworkStream 一起使用,还是已经缓冲了。
编辑:我只想减少对底层套接字流的读/写调用的数量。
解决方案
解决方案 就是使用两个独立的 BufferedStream
s,一个用于接收,一个用于发送。并且不要忘记刷新发送 BufferedStream
适当地。
即使在 2018 年,这个问题似乎也很难得到令人满意的答案,为了人性,我的两点意见是:
这 NetworkStream
是 在操作系统端缓冲。但是,这并不意味着没有理由在 .net 端进行缓冲。TCP 在“写-读”(重复)上表现良好,但在“写-写-读”上由于延迟确认等原因而停滞。
如果你像我一样,有一堆低于标准的协议代码要带入二十一世纪,那么你想要缓冲。
或者, ,如果您坚持上述,您也可以仅缓冲读取/接收或仅写入/发送,并使用 NetworkStream
直接发送给另一方,具体取决于代码的损坏程度。 你只需要保持一致!
什么 BufferedStream
文档未能充分说明的是您应该 仅当您的流可查找时才切换读取和写入. 。这是因为它在同一个缓冲区中缓冲读取和写入。 BufferedStream
根本不适合 NetworkStream
.
正如 Marc 指出的那样,造成这种缺陷的原因是两个流合并为一个 NetworkStream,这并不是 .net 最伟大的设计决策之一。
其他提示
NetworkStream 已被缓冲。所有接收到的数据都保存在缓冲区中等待您读取。对 read 的调用要么非常快,要么会阻塞等待从网络上的其他对等点接收数据,BufferedStream 在这两种情况下都无济于事。
如果您担心阻塞,那么您可以考虑将底层套接字切换到非阻塞模式。
A BufferedStream
只是减少对底层流(可能受 IO/硬件限制)的读/写调用的数量。它无法提供寻道功能(事实上,缓冲和寻道在很多方面是相互矛盾的)。
为什么需要寻求?也许首先将流复制到可查找的内容 - a MemoryStream
或一个 FileStream
- 然后从第二个可搜索流中进行实际工作。
您有特定的目的吗?我也许可以建议更合适的选项和更多细节......
尤其:注意 NetworkStream
是一个好奇心 - 对于大多数流,读/写与同一个物理流相关;然而,一个 NetworkStream
实际上代表两个完全独立的管道;读和写完全无关。同样,你无法寻找已经从你身边掠过的字节......你可以 跳过 数据,但是最好通过做一些事情来完成 Read
操作并丢弃数据。