系统调用 accept 源码分析
注:本文分析基于 3.10.0-693.el7 内核版本,即 CentOS 7.4
1、函数原型
1 |
|
2、内核实现
1 |
|
最终调用的是 SYSCALL_DEFINE4()
1 |
|
新建 socket 结构体,然后也分配一个 file 结构体,并将这两个结构体相关联,这些操作 socket()
系统调用里也有,包括后面和文件描述符 fd 关联,总的就是将 fd 和文件系统以及网络联系到一起,形成一切皆文件的 Unix 理念。
有了 socket 结构体,那肯定需要有对应的 sock 结构体,这就是 sock->ops->accept()
所做的了。sock->ops
指向 inet_stream_ops
1 |
|
所以调用的就是 inet_accept()
1 |
|
然后调用对应协议的 accept 函数,对于TCP协议,
1 |
|
因此TCP协议里,对应的 accep t函数就是 inet_csk_accept()
。
1 |
|
获取可 accept 的请求,如果此时尚未有客户端发起连接,那就睡眠直到有请求到来,或者如果用户设置了超时时间,也会超时返回。另外,也有可能被信号打断。
1 |
|
当有请求到来后,就从全连接队列里取出这个请求,返回请求指向的 sock 结构体,这个结构体也就是在第三次握手中新建的 child sock。然后将这个 sock 结构体和 accept 最开始创建的 socket 结构体关联,通过 sock_graft()
完成关联。
1 |
|
最后,调用 fd_install()
将 fd 安装到对应 file 结构体中,完成 accept()
的调用。
概括下 accept 的大概流程:
- 创建一个 socket 结构体
- 获取一个未使用的文件描述符 fd
- 创建一个 file 结构体,并和 socket 关联
- 从全连接队列中获取客户端发来的请求
- 根据请求获取之前新建的 sock 结构体返回
- 将请求中的 sock 结构体和开始分配的 socket 结构体关联
- 将文件描述符 fd 和文件结构体 file 关联,并返回 fd 供用户使用
Reference
系统调用 accept 源码分析
https://flepeng.github.io/002-Linux-41-系统调用-系统调用-accept-源码分析/