TCP三次握手
概述
TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换 TCP窗口大小信息。在socket编程中,这一过程由客户端执行connect来触发。
流程图
- 第一次握手
建立连接时,客户端发送连接请求报文段(SYN=1,seq=x),然后客户端进入SYN_SEND状态,等待服务器的确认; - 第二次握手
服务器收到SYN报文段,需要对这个SYN报文段进行确认(ACK=1, ack=x+1)。同时服务器也要发送SYN请求信息(SYN=1,seq=y)。服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态; - 第三次握手
客户端收到服务器的SYN+ACK报文段。然后向服务器发送ACK报文段(ACK=1,seq=x+1,ack=y+1),这个报文段发送后,客户端进入ESTABLISHED状态。服务器端接收后进入ESTABLISHED状态,完成TCP三次握手。
随后客户端与服务器端之间可以开始传输数据了。
为什么要三次握手
两次就可以完成,为什么非要进行三次呢?在谢希仁的《计算机网络》中是这样说的:
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
在书中同时举了一个例子,如下:
“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
这就很明白了,为了防止了服务器端的一直等待而浪费资源。
其他问题
首次握手的隐患
SYN Flood的问题起因分析
Server收到SYN之后的流程为:
- Server收到Client的SYN,回复SYN-ACK的时候未收到ACK确认
- Server不断重试直至超时才断开连接释放资源(Linux默认63s超时,即重试5次:1,2,4,8,16)
如果有非法Client大量发起SYN请求直至占满SYN队列,则会出现SYN Flood问题,导致后续正常的Client无法成功连接。
SYN Flood的防护措施
- SYN队列满后,通过tcp_syncookies参数回发SYN Cookie
- 若为正常连接则客户端会回发SYN Cookie,然后直接建立连接
建立连接后,Client出现故障怎么办
保活机制
- 向对方发送保活探测报文,如果未收到响应则继续发送
- 尝试次数达到保活探测数仍未收到响应则中断连接