坑爹的.NET BufferedStream

简介: BufferedStream的作用是给另一流上的读写操作添加一个缓冲层,改进IO效率。但最近在使用Npgsql(内部使用BufferedStream包装了NetworkStream)的过程中,发现BufferedStream有2个严重的问题,或者可以说是Bug。
BufferedStream的作用是给另一流上的读写操作添加一个缓冲层,改进IO效率。但最近在使用Npgsql(内部使用BufferedStream包装了NetworkStream)的过程中,发现BufferedStream有2个严重的问题,或者可以说是Bug。

1)BufferedStream不能同时读写
BufferedStream同时提供了读和写的API(这可能也是Stream的悲哀,不像Java中严格区分读Stream和写Stream),但是却不能同时读写。通过反编译BufferedStream,发现其内部结构有点像是工作在半双工模式下的通信接口,可以交替读写,但这个交替读写是有Bug的。

BufferedStream内部只有一个缓冲区,由读写操作共用。
a)读的时候,如果发现缓冲区中有未写完的数据,则写完缓冲区中的数据到底层流并Flush。
b)写的时候,如果发现缓冲区中有未读完的数据,则通过Seek()回退掉未读完的数据。

这套逻辑看上去很美,但是并不是每个流都支持Seek(),比如NetworkStream。底层流是 NetworkStream的情况下就可能会莫名其妙的地方报出 NotSupportedException异常。

那在使用BufferedStream时,确保读完再写可不可以?
有些应用场景这一招管用,但至少对Npgsql不行。Npgsql严格按照发请求,读响应的逻辑和服务端通信。但却忘了 PostgreSQL中存在所谓的异步消息,PostgreSQL服务端可能会在通常的响应消息后面插入一个异步通知。如果响应消息和异步通知都被读入BufferedStream的内部缓冲区,但Npgsql在这一轮请求循环中,只读出了和请求对应的响应消息,那么下次发送请求时就会触发上面提到的NotSupportedException异常。

解决方法:
比较简单的解决方法是,使用2个BufferedStream对象包装同一个底层流,分别用于读和写。

2)Read()的不当阻塞

http://msdn.microsoft.com/zh-cn/library/system.io.bufferedstream.read(v=vs.80).aspx

  1. int Read([In, Out] byte[] array, int offset, int count)
  2. 读入 array 中的总字节数。如果可用的字节没有所请求的那么多,总字节数可能小于请求的字节数;或者如果在可读取任何数据前就已到达流的末尾,则为零。
当count小于BufferedStream对内部缓冲区的大小(默认4K),并且底层流中的有效数据小于count时,会导致 Read()方法无限阻塞。
这应该是个Bug,根据MSDN中Read()的API描述(和流的Read()方法的惯例),这时应该将底层流已有的数据返回。
相关文章
|
3月前
|
XML 开发框架 安全
分享92个NET源码,总有一款适合您
分享92个NET源码,总有一款适合您
19 0
|
3月前
|
开发框架 前端开发 JavaScript
分享86个NET源码,总有一款适合您
分享86个NET源码,总有一款适合您
18 0
|
3月前
|
SQL 开发框架 自然语言处理
分享77个NET源码,总有一款适合您
分享77个NET源码,总有一款适合您
38 1
|
3月前
|
SQL 开发框架 安全
分享84个NET源码,总有一款适合您
分享84个NET源码,总有一款适合您
22 1
|
3月前
|
开发框架 自然语言处理 负载均衡
分享91个NET源码,总有一款适合您
分享91个NET源码,总有一款适合您
22 2
|
3月前
|
SQL 开发框架 前端开发
分享65个NET源码,总有一款适合您
分享65个NET源码,总有一款适合您
32 1
|
3月前
|
供应链 前端开发 项目管理
分享88个NET源码,总有一款适合您
分享88个NET源码,总有一款适合您
35 3
|
3月前
|
开发框架 搜索推荐 .NET
分享66个NET源码,总有一款适合您
分享66个NET源码,总有一款适合您
18 0
|
SQL NoSQL 关系型数据库
.NET5真的来了,你准备好了吗?
.NET5真的来了,你准备好了吗?
140 0
.NET5真的来了,你准备好了吗?
一起谈.NET技术,20条.NET编码习惯
1、不要硬编string/ numeric,可以使用一些常量代替。 (提高可读性) int Count;Count = 100;private static const int ZERO  =  0;if(  Count  ==  ZERO ){// 执行一些操作} 2、对于字符串比较-使用String. Empty ,而不是""。
788 0

热门文章

最新文章