网络编程中的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是如何实现的,以后会继续去探究。
相关文章
使用 C 语言中的 goto 语句
发布时间:2023/05/07 浏览次数:79 分类:C语言
-
本文介绍了如何在 C 语言中使用 goto 语句。使用 goto 语句在 C 语言中实现循环 goto 关键字是 C 语言的一部分,它提供了一个做无条件跳转的结构。
Django 中的 Slug
发布时间:2023/05/04 浏览次数:173 分类:Python
-
本篇文章旨在定义一个 slug 以及我们如何使用 slug 字段在 Python 中使用 Django 获得独特的帖子。
在 Django 中按降序过滤查询集中的项目
发布时间:2023/05/04 浏览次数:157 分类:Python
-
在这个讲解中,学习如何借助 Django 中的 order_by() 方法按降序过滤出查询集中的项目。
Django ALLOWED_HOSTS 介绍
发布时间:2023/05/04 浏览次数:181 分类:Python
-
本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。
Django 中的 Select_related 方法
发布时间:2023/05/04 浏览次数:129 分类:Python
-
本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。
使用 Post 请求将数据发送到 Django 服务器
发布时间:2023/05/04 浏览次数:159 分类:Python
-
在这篇关于Django的讲解中,我们简要介绍了post和get请求以及如何在Django中用post实现CSRF token。
Django 返回 JSON
发布时间:2023/05/04 浏览次数:106 分类:Python
-
在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。
在 Django 中创建对象
发布时间:2023/05/04 浏览次数:59 分类:Python
-
本文的目的是解释什么是模型以及如何使用 create() 方法创建对象,并了解如何在 Django 中使用 save() 方法。