TCP 的三次握手
- client发送SYN到server,将状态修改为SYN_SEND,如果server收到请求,则将状态修改为SYN_RCVD,并把该请求放到syns queue队列中。
- server回复SYN+ACK给client,如果client收到请求,则将状态修改为ESTABLISHED,并发送ACK给server。
- server收到ACK,将状态修改为ESTABLISHED,并把该请求从syns queue中放到accept queue。
backlog参数的含义
TCP建立连接是要进行三次握手,但是否完成三次握手后,服务器就处理(accept)呢?
backlog其实是一个连接队列。
Linux内核2.2之前
在Linux内核2.2之前,backlog大小包括半连接状态和全连接状态两种队列大小。
半连接状态为:
服务器处于Listen状态时收到客户端SYN报文时放入半连接队列中,即SYN queue(服务器端口状态为:SYN_RCVD)。
全连接状态为:
TCP的连接状态从服务器(SYN+ACK)响应客户端后,到客户端的ACK报文到达服务器之前,则一直保留在半连接状态中;
当服务器接收到客户端的ACK报文后,该条目将从半连接队列搬到全连接队列尾部,即 accept queue (服务器端口状态为:ESTABLISHED)。
Linux内核2.2之后
在Linux内核2.2之后,分离为两个backlog来分别限制半连接(SYN_RCVD状态)队列大小和全连接(ESTABLISHED状态)队列大小。
SYN queue 队列长度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,默认为2048。
Accept queue 队列长度由 /proc/sys/net/core/somaxconn 和使用listen函数时传入的参数,二者取最小值。默认为128。
- 在Linux内核2.4.25之前,是写死在代码常量 SOMAXCONN ;
- 在Linux内核2.4.25之后,在配置文件 /proc/sys/net/core/somaxconn 中直接修改, 或者在
/etc/sysctl.conf 中配置 net.core.somaxconn = 128 。
两个队列在连接过程中所处的位置如下图所示:
ss
用来显示处于活动状态的套接字信息。
ss命令可以用来获取socket统计信息,它可以显示和netstat类似的内容。
但ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息,而且比netstat更快速更高效。
当服务器的socket连接数量变得非常大时,无论是使用netstat命令还是直接cat /proc/net/tcp,执行速度都会很慢。可能你不会有切身的感受,但请相信我,当服务器维持的连接达到上万个的时候,使用netstat等于浪费生命,而用ss才是节省时间。
ss快的秘诀在于,它利用到了TCP协议栈中tcp_diag。
tcp_diag是一个用于分析统计的模块,可以获得Linux 内核中第一手的信息,这就确保了ss的快捷高效。
当然,如果你的系统中没有tcp_diag,ss也可以正常运行,只是效率会变得稍慢。
Recv-Q和Send-Q
使用 ss 获取到的 Recv-Q/Send-Q 在 LISTEN 状态以及非 LISTEN 状态所表达的含义是不同的。
LISTEN 状态:
- Recv-Q 表示的当前等待服务端调用 accept 完成三次握手的 listen backlog 数值,也就是说,当客户端通过connect() 去连接正在 listen() 的服务端时,这些连接会一直处于这个 queue 里面直到被服务端 accept();
- Send-Q 表示的则是最大的 listen backlog 数值,这就是 min(backlog, somaxconn)的值。(backlog时listen时传入的参数)
非 LISTEN 状态
- Recv-Q 表示 receive queue 中的 bytes 数量;
- Send-Q 表示 send queue 中的 bytes 数值。
netstat
- Recv-Q:The count of bytes not copied by the user program connected to this socket.
- Send-Q:The count of bytes not acknowledged by the remote host.