网络编程中的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

回到顶部