func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
if len(buf) < min {
return 0, ErrShortBuffer
}
**for n < min && err == nil {
var nn int
nn, err = r.Read(buf[n:])
n += nn
}**
if n >= min {
err = nil
} else if n > 0 && err == EOF {
err = ErrUnexpectedEOF
}
return
}
共 20 个回复
DRYGGJS
请问解决了吗,很好奇原因。。
yaohong
没有解决。。。。
me@bzza.com
io.ReadFull本来意思就是读完所有的意思,直到遇上出错或读取的内容长度>=len(buf)
传过去的io.Reader中的Read方法是你定义的,如何read,read多少都是你定义的,修改你的read
重要的内容说三次:Read方法是你定义的,Read方法是你定义的,Read方法是你定义的。
yaohong
这里的Read是TcpConn实现的(也是系统库)。。不是我自己实现的。。
HobaiRiku
看明白了又没看太明白二楼的意思,但是看了golang的ReadFull文档以及在example中试了一下,在strings.NewReader()下,
n是不会超出len(buf)的
,所以继续看文档的,当你把src/net/net.go
180行左右的代码:和二楼贴出的ReadFull调用的ReadAtLeast的源码(
src/io/io.go
304行左右),你就会发现,ReadFull文档中的这句话就是现在你的这种情况:也就是说,ReadFull会读取io.Reader中的所有数据,即使给的buf长度小于数据大小,其实这时候读取数据是已经出错的,但当已经读满了buf长度,被
err=nil
了,也就出现n=27,err=nil
的情况。tcpConn的read一下子直接读了27
,而像stringReader是用copy(),返回的n不会大于buf长度。不知道分析得对不对。
yaohong
感觉都被带偏了。。重点不是io.ReadFull

我在发下截图吧
是TcpConn.Read 读取的返回长度大于传入BUFF的长度。
yaohong
传入BUFF的长度是4
而TCPConn.Read返回的n是28
yaohong
这个是调试器断点的截图
HobaiRiku
我不确定你这个
self.conn
转换为*TCPConn
是什么个意思,的确TCPConn经过一系列io的Read后,不会在一次处理超过buf长度的数据,所以你自己可以断点调试一下到底这个Read走的是哪里,也许实际走的Read是不一样的呢?还是二楼的那句话,Read是自己实现的,我觉得其实n和buf的长度没有直接关系,并没有规定n一定不能大于buf的长度。yaohong
这个self.conn 就是net.Conn 这是为了直观可以一眼就知道是TCPConn。
这个read是 官方库自带的。。。
yaohong
在强调一下。。
Read不是我自己实现的。是net.TcpConn 的方法
yaohong
问题就是系统库自带的
tcpConn.Read 读取的数据长度大于传入BUFF的长度
我传入的len(buff)=4 ,结果告诉我返回了28
HobaiRiku
你不用强调什么,如果的就是Conn接口,你断点到源码调试就知道为什么会一次读取28了,我自己简单断点看到是没走超过buf长度的,超过会保留到下一次read,但底层conn和poll、io之类的我也看不太懂,所以也不能说出个什么。
yaohong
我这个并不是100%出现。。
是在做压力测试的时候才偶先。。。。
yaohong
就什么办法能调试到源码
yaohong
4344233 楼上的大佬
DRYGGJS
兄弟留个联系方式,一起解决,比较好奇这种问题
我qq 2667350913
DRYGGJS
又要2个月才看消息吗。。
rocket
我觉得楼主可以用 bufio 防止这个错误。
xigualala
这个self.conn转换为*TCPConn是什么个意思,的确TCPConn经过一系列上海快3io的Read后,不会在一次处理超过buf长度的数据,所以你自己可以断点调试一下到底这个Read走的是哪里,也许实际走的Read是不一样的呢?还是二楼的幸运飞艇 那句话,Read是自己实现的,我觉得其实n和buf的长度没有直接关系,并没有规定n一定不能大于buf的长度。