版本:linux 4.18.1
作为学习笔记,本篇只讨论常规的交互过程,旨在理清 linux 内核对 TCP 相关的信息管理。
在连接开启以前,服务端 首先要调用 bind() 将 sock 绑定到某个端口,然后调用 listen() 使 sock 处于 被动监听状态,然后客户端才可以向服务端发起连接请求。
bind()
bind() 函数主要流程:
首先根据 端口号 计算一个 hash 值,然后通过这个 hash 值在定位到 inet_bind_hashbucket 某个 slot;
定位到 slot 后,遍历指向的链表,看这个端口是否已经存在:
如果端口不存在,就新建一个 inet_bind_bucket 并添加到链表中;
如果端口已经存在,则要检查是否已经有连接使用了该端口:
如果已经有连接使用,则报错(不考虑端口重用);
执行到这里,已经有一个 inet_bind_bucket 表示这个端口了,接下来,只要把调用 bind 函数的 sock 加入到 inet_bind_bucket.owners 即可。
listen()
listen() 函数主要流程:
首先将 sock 状态设置为 TCP_LISTEN;
然后根据端口号计算哈希值定位到 listening_hash 某个 slot,将 sock 添加进来;
最后按类似的方式,把 sock 也添加到 lhash2 中。
下图表示某个服务器程序绑定端口 9090 ,调用 bind 和 listen 函数后,内核中保存的 tcp 相关信息。