迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

网络编程中的read问题

作者:迹忆客 最近更新:2022/12/26 浏览次数:

在描述问题之前,先看一下在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是如何实现的,以后会继续去探究。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

使用 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 ALLOWED_HOSTS 介绍

发布时间:2023/05/04 浏览次数:181 分类:Python

本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。

Django 中的 Select_related 方法

发布时间:2023/05/04 浏览次数:129 分类:Python

本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。

在 Django 中上传媒体文件

发布时间:2023/05/04 浏览次数:198 分类:Python

在本文中,我们简要介绍了媒体文件以及如何在 Django 项目中操作媒体文件。

Django 返回 JSON

发布时间:2023/05/04 浏览次数:106 分类:Python

在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。

在 Django 中创建对象

发布时间:2023/05/04 浏览次数:59 分类:Python

本文的目的是解释什么是模型以及如何使用 create() 方法创建对象,并了解如何在 Django 中使用 save() 方法。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便