1.TCP的三次握手和四次挥手
1.1.TCP三次握手(建立通道)
<1>LISTEN
服务端经过 socket,bind,listen 函数之后进入此状态,开始进入监听状态;
<2> SYN_SENT
第一次握手,客户端调用 connect,发送 SYN报文给服务器端。若服务端不能连接,则直接进入初始的CLOSED状态;
<3> SYN_RCVD
第二次握手,服务端接收到客户端的SYN报文,服务端由 LISTEN 进入 SYN_RCVD状态,同时回应一个SYN+ACK报文给客户端;
<4> ESTABLISHED
第三次握手,客户端接收到服务端的SYN+ACK报文后,回应一个 ACK报文后,客户端进入 ESTABLISHED 状态,表明客户端已经准备好;服务端收到客户端的 ACK报文 之后会从 SYN_RCVD 状态转移到 ESTABLISHED 状态,表明服务端已经准备好;
注意:TCP需要两端都准备好才可以进行数据传输,所以ESTABLISHED也可以说是一个数据传送状态;
1.2.TCP四次挥手(断开通道)
<1>FIN_WAIT_1
![](/qrcode.jpg)
第一次挥手,主动关闭方(既可是客户端,也可是服务端)终止连接时,调用 close() 发送 FIN报文给对方,然后等待对方返回 ACK;
<2>CLOSE_WAIT
接收到FIN报文后,被动关闭的一方进入此状态,接收到FIN,同时发送 ACK;
TCP关闭是全双工过程,这里主动关闭方执行了关闭,被动方也需要调用close() 关闭,CLOSE_WAIT就是处于这个状态,等待发送 FIN,发送了FIN被动方进入 LAST_ACK 状态;
<3>FIN_WAIT_2
主动关闭方先发送FIN,然后接收到被动方返回的 ACK 后进入此状态;
<4>LAST_ACK
被动方发起关闭请求(发送 FIN),进入此状态。当接收到主动关闭方回应的ACK 时进入CLOSED状态;
<5>CLOSING
两边同时发起关闭请求时,会由FIN_WAIT_1 进入此状态,等待返回ACK;
<6>TIME_WAIT
共有三个状态会进入该状态
- 由CLOSING进入:同时发起关闭情况下,当主动端接收到ACK后,进入此状态,实际上这里的同时是这样的情况:客户端发起关闭请求,发送FIN之后等待服务器端回应ACK,但此时服务器端同时也发起关闭请求,也发送了FIN,并且被客户端先于ACK接收到;
- 由FIN_WAIT_1进入:发起关闭后,发送了FIN,等待ACK的时候,正好被动方(服务器端)也发起关闭请求,发送了FIN,这时客户端接收到了先前ACK,也收到了对方的FIN,然后发送ACK(对对方FIN的回应),与CLOSING进入的状态不同的是接收到FIN和ACK的先后顺序;
- 由FIN_WAIT_2进入:这是不同时的情况,主动方在完成自身发起的主动关闭请求后,接收到了对方发送过来的FIN,然后回应 ACK;
TIME_WAIT的作用
情况1:若最后回应的ACK丢失,那么被动关闭方将继续发送最终的FIN报文:
<1>若主动关闭方维护TIME_WAIT状态,主动关闭方将重发最后的ACK,来实现全双工关闭;
<2>若主动关闭方没有TIME_WAIT状态,将处于CLOSED状态,那么将发送RST报文。服务端收到后RST后,解释成一个错误,也就无法实现全双工关闭(可能是主动方单方的关闭);
情况2:若通信双方都已经调用了close(),没有TIME_WAIT状态,将到达CLOSED状态
<1>现在若新连接被建立(使用原有的IP地址和端口),若原先的连接中还有数据报残存在网络之中,这样新的连接建立以后传输的数据极有可能就是原先的连接的数据报。
因此:TCP不允许从处于TIME_WAIT状态的socket建立一个连接,且处于TIME_WAIT状态的socket在等待了2MSL时间后,才会转变为CLOSED状态;
1.3.RST标志位
RST表示复位,用来关闭异常或不存在的连接。发送RST包时,不必等缓冲区的包都发出去(不像上面的FIN包),直接发送RST包。而接收端收到RST包后,也不必发送ACK包来确认,直接关闭连接。