调用 read 后实际发生了什么:
n = read(fd, buf, try_read_size);
这里的 fd 是一个 TCP 套接字描述符。 buf 是缓冲区。 try_read_size 是程序尝试读取的字节数。
我想这最终可能会调用对内核的系统调用。但是谁能提供一些细节?说glibc或内核源代码中的源代码实现?
最佳答案
从高层次的角度来看,这就是发生的事情:
- 调用glibc提供的包装函数
- 包装函数将堆栈上传递的参数放入寄存器中,并在专用于此目的的寄存器中设置系统调用编号(例如 x86 上的 EAX)
- 包装函数执行陷阱或等效指令(例如 SYSENTER)
- CPU切换到ring0,调用trap handler
- 陷阱处理程序检查系统调用号的有效性,并在内核函数的跳转表中查找它
- 相应的内核函数检查参数是否有效(例如
buf
到buf+try_read_size
指的是可访问的内存页,fd
是实际上是一个文件描述符)。如果出现问题,将生成负错误代码(例如 -EFAULT),CPU 将切换回用户模式并且调用返回到包装器。 - 根据文件描述符的类型调用另一个函数(在您的情况下是套接字,但可以从 block 设备或
proc
条目或更奇特的东西读取) - 检查套接字的输入缓冲区:
- 如果缓冲区中有一些数据,
min(available, try_read_size)
被复制到buf
,数量被写入返回码寄存器(x86上为EAX) ),cpu 切换回用户模式,调用返回包装器。 - 如果输入缓冲区为空
- 如果连接已经关闭,则将零写入返回码寄存器,cpu 切换回用户模式,调用返回包装器
- 如果连接没有被关闭
- 如果套接字是非阻塞的,则将负错误代码 (
-EAGAIN
) 写入返回代码寄存器,cpu 切换回用户模式并且调用返回包装器。 - 如果套接字不是非阻塞的,则进程挂起
- 如果套接字是非阻塞的,则将负错误代码 (
- 如果缓冲区中有一些数据,
- 包装函数检查返回值是否为负(错误)。
- 如果为正或零,则返回值。
- 如果为负,则将 errno 设置为负值(报告正错误)并返回 -1
关于linux - 为 Linux 套接字调用读取后会发生什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10226294/