好记性不如烂笔头,本文是tcp协议部分基础知识的整理。
tcp建连、断连
示意图

为什么需要三次握手?
- 防止失效的连接请求到达服务器。
- 具体描述:如果client发送的连接请求SYN包在网络中滞留了较长时间,server最终仍会收到并发回连接确认SYN+ACK。而client等待一个超时时间后,认为刚才滞留的连接请求包丢失了,则会重新发送SYN包发起连接请求。如果不进行第三次握手,那么server收到滞留的SYN包就打开的连接是无效的;如果有第三次握手,那么client会忽略server对滞留的SYN包的响应SYN+ACK,不回复ACK包,server收不到第三次握手ACK包就不会新建连接。
tcp面向连接什么含义?
为了在client和server间维护连接,需建立一定的数据结构来维护双方的交互状态,用这样的数据结构来保证面向连接的特性。
为什么需要四次挥手?
一端发送FIN包请求释放连接,对端收到这个FIN报文后进入了CLOSE_WAIT
状态。这个状态下,仍然可以向对方发送未发送完毕的数据,数据发送完毕后也要向对端发送FIN报文释放连接,忘了发FIN包(调用close())会导致bug。也就是说,TCP是全双工传输,两端都必须发送FIN包,才能完全断开连接。
TIME_WAIT状态
主动发送FIN包的一端,在收到对端的FIN报文后进入TIME_WAIT
状态,这个状态一般要保持一个较长的时间2MSL。原因如下:
- 确保最后一个应答FIN的报文ACK能够到达。因为如果对端没有收到ACK应答,则会重发FIN包。
- 让当前连接在网络中可能的所有报文达到生存期上限后消失,使得下一个新的连接不会收到旧的连接的数据。
三次握手内核实现原理示意图

队列长度配置
- SYN队列长度配置:
net.ipv4.tcp_max_syn_backlog = 8192 #SYN_RCVD状态连接的最大个数
; - ACCEPT队列长度:
- 系统全局:
net.core.somaxconn = 262144 #系统全局ACCPET队列最大长度的配置
- 应用层: socket API listen传参控制
- 系统全局:
SYN攻击
攻击者迅速伪造不同IP地址的SYN报文,快速占满SYN队列,使得正常的SYN包无法加入队列。
应对SYN攻击的参数
net.core.netdev_max_backlog = 262144 #接收自网卡、但是未被内核协议栈处理的IP报文队列长度
net.ipv4.tcp_max_syn_backlog = 8192 #SYN_RCVD状态(半)连接的最大个数
net.ipv4.tcp_abort_on_overflow = 1 #设置为1时表示: 队列满则响应RST包,丢弃连接
tcp_syncookies
net.ipv4.tcp_syncookies = 1 #启用tcp cookie, 使得SYN队列满仍能建立连接
控制TCP三次握手的参数
-
SYN_SENT状态
net.ip4.tcp_syn_retries = 6 #主动建立连接,发送SYN的重试次数
net.ipv4.ip_local_port_range = 32768 60999 #建立连接时的本地端口可选范围
-
SYN_RCVD状态
net.ipv4.tcp_max_syn_backlog = 8192 #SYN_RCVD状态(半)连接的最大个数
net.ipv4.tcp_synack_retries = 3 #被动建立连接时,发送SYN/ACK的重试次数
TFO(TCP Fast Open)
配置: net.ipv4.tcp_fastopen
。(注意:内核版本要求在Linux 3.7以上)
可选值:
- 0: 关闭(默认)
- 1: 作为客户端时可以使用TFO
- 2: 作为服务端时可以使用TFO
- 3: 都可以使用TFO,无论是作为服务端还是客户端
示意图
