网络编程中的read问题
在描述问题之前,先看一下在go语言的net编程中read
函数是怎么使用的。
var rb = make([]byte, 1024)
tcpAddr,err:=net.ResolveTCPAddr(NETWORK, Host+":"+Port)
if err != nil {
log.Panic(err.Error())
}
listener,err := net.ListenTCP(NETWORK, tcpAddr)
if err != nil {
log.Panic(err.Error())
}
conn,err := listener.AcceptTCP()
if err != nil {
log.Panic(err.Error())
}
num, err := conn.Read(rb)
net中的Read
是用来读取连接中的数据,将读取的数据放入buffer中,也就是上面代码中的rb 变量。返回的是实际读取到的字节数——num。 在最近的一个项目中,使用net进行开发的时候。碰到了一个Read问题,首先部分代码逻辑是这样的。
var rb = make([]byte,BufferSize)
for {
num, err = reader.Read(rb)
Len += num
if err != nil {
if err == io.EOF {
break
}
client.Err = err
return-1, "", err
}
buffer.Write(rb[0:num])
if num < BufferSize {
break
}
}
在上面的代码中,使用了Read
方法的返回值作为判断,如果实际读取的字节小于期望读取的字节,说明已经读取完成了,则不再继续读取。 我们设定,BufferSize为1024字节,当客户端发送的数据小于1024字节的时候,实际读取到的肯定是小于BufferSize的。如果大于1024字节,那么num 等于 BufferSize 则继续进行下一次读取,直到返回的num小于BufferSize。(排除最后一次读取正好等于BufferSize的情况)。
上面的逻辑在 Mac系统中运行的很好。但是当把项目放到 linux (centos,ubuntu)系统中运行时却出现了问题,没有读取完成就退出读取了,连接中有超过BufferSize的数据,但是Read返回的num却小于BufferSize。 查看Read函数的底层实现,其实是调用的系统的 libc_read
funcread(fd int, p []byte)(n int, err error) {
var _p0 unsafe.Pointer
iflen(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
funclibc_read_trampoline()
//go:linkname libc_read libc_read
//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
所以,在不同的系统上运行的效果也不一样了。 查看linux系统中对read函数的解释
$ man 2 read
# On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number.
# It is not an error if this number is smaller than the number of bytes requested;
# this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
# On error, -1 is returned,and errno is set appropriately.
# In this case it is left unspecified whether the file position (if any) changes.
意思就是说,read
返回的值比期望读取字节数要小,这是正常的。因为,一种情况是实际读取的字节数就是比期望的要少(可能是因为实际数据就是少的,或者是从pipe中读,也可能是在终端读取);另一种就是特殊的情况在读取的过程中被信号中断了。这些都会导致一次read返回的读取字节数比期望读取的字节数小。 而在 Mac 系统中,查看read
$ man 2 read
# If successful, the number of bytes actually read is returned.
# Upon reading end-of-file, zero is returned.
# Otherwise, a -1 is returned and the global variable errno is set to indicate the error.
这就是说,在Mac中,读取的实际字节数是符合期望值的。如果实际数据少于期望值,则当次read返回的小于期望值;如果实际数据大于期望值,则档次read返回的等于期望值。没有linux中的那些特殊情况。
这也就解释了,我上面的代码在Mac中能正常运行,而到了linux中却不能正常运行。
上面的结论是从c的read中推导出来的,但是我相信原理都是相同的。根据此是可以用go来写正确的代码的。具体关于系统对于 libc_read是如何实现的,以后会继续去探究。
本文转载自:迹忆客(https://www.jiyik.com)
以上是 网络编程中的read问题 的全部内容, 来源链接: utcz.com/z/290205.html