网络编程中的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
func read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(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
}
func libc_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是如何实现的,以后会继续去探究。
相关文章
在 JavaScript 中验证 Google ReCaptcha 第 2 版
发布时间:2024/03/23 浏览次数:193 分类:JavaScript
-
本文演示了如何在 JavaScript 中验证 Google Recaptcha。
C# 中的 goto 语句
发布时间:2024/02/02 浏览次数:184 分类:编程语言
-
本教程演示了如何在 C# 中使用 goto 以及何时使用它会有所帮助本教程将演示如何在 C# 中使用 goto 语法,并提供一些代码中的实际使用示例。
在 Python 中是否存在 goto 语句
发布时间:2023/12/20 浏览次数:197 分类:Python
-
本文为你提供了 Python 中是否存在 goto 语句的答案。本文为你提供了 Python 中是否存在 goto 语句的答案。基本上,Python 不支持 goto 语句。
避免 Python中的 TypeError: Input Expected at Most 1 Argument, Got 3 错误
发布时间:2023/07/08 浏览次数:671 分类:Python
-
Python 中避免 TypeError: input Expected atmost 1 argument, got 3 Error在Python编程中,我们有两个内置方法来获取用户的输入:input(prompt)和 raw_input(prompt)。
使用 Python 将文件上传到 Google 云端硬盘
发布时间:2023/06/15 浏览次数:544 分类:Python
-
本文将介绍我们如何使用 Python 将文件上传到云盘,以 Google Drive 为例。 为此,我们将使用 Google Drive API。
Python 错误 Valueerror: Expected 2d Array, Got 1d Array Instead
发布时间:2023/05/30 浏览次数:293 分类:Python
-
当我们在 numpy 中传递一维数组而不是二维数组时,会发生错误 ValueError: Expected 2D array, got 1D array instead 。如您所知,每种编程语言都会遇到很多错误,有些是在运行时,有些是在编译时。 Pyth