tcp连接建立,常遇到的面试题

40 阅读2分钟

客户端

客户端在发起 connect 系统调用的时候,主要工作就是端口选择[1]。

服务端

半连接队列和建立连接队列

调用fd=socket(),然后bind(),listen(),创建了一个监听socket。其在内核对应一个 struct sock* sk对象,该对象有一个半连接队列reqsk_queue,和一个接收连接队列acceptq(也称为 “已完成连接队列”)。

使用 ss -lnt(主意,-l选项是必须的,查看listen socket的意思):

State Recv-Q Send-Q Local Address:Port 
LISTEN 0 128 0.0.0.0:80 
LISTEN 5 50 [::]:22

在 ss -ltn 的输出中,Send-Q 和 Recv-Q 的含义与普通已连接套接字不同,专门针对监听状态的特性设计:

1. Send-Q(对于 LISTEN 状态)

表示半连接队列(SYN 队列)的当前使用长度,即已收到客户端 SYN 报文但尚未完成三次握手的连接数量。
其值的上限由内核参数 net.ipv4.tcp_max_syn_backlog 和 net.core.somaxconn 共同决定(取两者较小值)。

2. Recv-Q(对于 LISTEN 状态)

表示接收连接队列(accept 队列)的当前使用长度,即已完成三次握手、等待应用程序调用 accept() 提取的连接数量。
其值的上限由 listen(backlog) 参数和内核参数 net.core.somaxconn 共同决定(取两者较小值)。

总结:
server先创建了一个监听socket,有两个队列。收到客户端syn包,在半连接队列里添加一个对象,记录了客户端ip 端口 序列号等信息;并发送了syn/ack,这也是用send-Q表示半连接队列的原因。 然后收到客户端ack,从半连接队列里把对应的对象取出来,放到全连接队列里。应用程序调用accept是从全连接队列里拿一个对象,创建一个新的socket。伺候完客户端和该新的socket通信,和listen socket就没有关系了。这个新的socket有接受队列,发送队列,队列里都是mbuf。

参考文档:
[1] mp.weixin.qq.com/s/7Cum6Y28H…