Linux套接字调用读取后会发生什么 [英] what happens after read is called for a Linux socket

查看:39
本文介绍了Linux套接字调用读取后会发生什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

调用read之后实际发生的事情:

What actually happens after calling read:

n = read(fd, buf, try_read_size);

此处fd是TCP套接字描述符.buf是缓冲区.try_read_size是程序尝试读取的字节数.

here fd is a TCP socket descriptor. buf is the buffer. try_read_size is the number of bytes that the program tries to read.

我想这可能最终会调用对内核的系统调用.但是有人可以提供一些细节吗?说glibc还是内核源代码中的源代码实现?

I guess this may finally invokes a system call to the kernel. But could anyone provide some details? say the source code implementation in glibc or kernel source?

推荐答案

从高层的角度来看,会发生以下情况:

From a high-level perspective, this is what happens:

  • 由glibc提供的包装器函数称为
  • wrapper函数将在堆栈上传递的参数放入寄存器中,并在专用于此目的的寄存器中设置系统调用号(例如x86上的EAX)
  • 包装函数执行陷阱或等效指令(例如SYSENTER)
  • CPU切换到ring0,并调用陷阱处理程序
  • 陷阱处理程序检查系统调用号的有效性,并在跳转表中查找到内核函数
  • 各自的内核函数检查参数是否有效(例如,范围 buf buf + try_read_size 指的是可访问的内存页面, fd 是确实是一个文件描述符).如果有问题,则会生成一个负错误代码(例如-EFAULT),然后将cpu切换回用户模式,然后调用返回到包装器.
  • 根据文件描述符的类型(在您的情况下为套接字,但可以从块设备或 proc 条目或其他更奇特的条目读取)来调用另一种函数
  • 已检查套接字的输入缓冲区:
    • 如果缓冲区中有一些数据,则将 min(available,try_read_size)复制到 buf ,该数量将写入返回码寄存器(x86上的EAX)),则cpu切换回用户模式,并且调用返回到包装器.
    • 如果输入缓冲区为空
      • 如果连接已关闭,则将零写入返回码寄存器,将cpu切换回用户模式,然后调用返回到包装器
      • 如果连接未关闭
        • 如果套接字未阻塞,则将负错误代码( -EAGAIN )写入返回代码寄存器,CPU切换回用户模式,并且调用返回到包装器.
        • 如果套接字是 not non-blocking
        • ,则该过程将被挂起
        • A wrapper function provided by glibc is called
        • The wrapper function puts the parameters passed on the stack into registers and sets the syscall number in the register dedicated for that purpose (e.g. EAX on x86)
        • The wrapper function executes a trap or equivalent instruction (e.g. SYSENTER)
        • The CPU switches to ring0, and the trap handler is invoked
        • The trap handler checks the syscall number for validity and looks it up in a jump table to kernel functions
        • The respective kernel function checks whether arguments are valid (e.g. the range buf to buf+try_read_size refers to accessible memory pages, fd is really a file descriptor). If something is amiss, a negative error code (e.g. -EFAULT) is generated, the cpu is switched back to user mode and the call returns to the wrapper.
        • Another function is called depending on the file descriptor's type (in your case a socket, but one could read from a block device or a proc entry or something more exotic)
        • The socket's input buffer is checked:
          • If there is some data in the buffer, min(available, try_read_size) is copied to buf, the amount is written to the return code register (EAX on x86), the cpu is switched back to user mode and the call returns to the wrapper.
          • If the input buffer is empty
            • If the connection has been closed, zero is written to the return code register, the cpu is switched back to user mode and the call returns to the wrapper
            • If the connection has not been closed
              • A negative error code (-EAGAIN) is written to the return code register if the socket is nonblocking, the cpu is switched back to user mode and the call returns to the wrapper.
              • The process is suspended if the socket is not non-blocking
              • 如果为正数或零,则返回值.
              • 如果为负,则将errno设置为负值(报告为错误)并返回-1
              • If positive or zero, it returns the value.
              • If negative, it sets errno to the negated value (a positive error is reported) and returns -1

              这篇关于Linux套接字调用读取后会发生什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆