tcp 的建立与断开
tcp客户端与服务端的三次握手和四次挥手大概的流程都知道,但是涉及一些细节还是要重新屡一下。
客户端的握手与挥手
连接
- client初始处于CLOSED状态,调用connect()函数向服务器发送连接请求(应用进程主动打开,发:SYN)后进入SYN_SENT。
- 收到来自服务器的确认报文(收:SYN,ACK)后,回复ack(发:ACK),然后进入ESTABLISHED状态。
- 如果收到的报文(收:SYN)只有SYN没有ACK,客户端就进入了SYN_RCV状态,如果再收到RST报文就进入了LISTEN状态;如果应用程序关闭,则进入FIN_WAIT_1状态。这些都是非正常的状态迁移。
断开
- 调用close()函数发送FIN报文,进入FIN_WAIT_1状态,此时有三个路径,根据收到的确认报文来选择;
- 如果收到FIN,表示server几乎与client同时调用close()函数想结束连接。就进入了CLOSEING状态,然后收到ACK后进入了TIME_WAIT状态;
- 如果收到FIN+ACK,这就是三次挥手了,进入TIME_WAIT状态;
- 如果只收到ACK,表示server端还有要传输的数据,需要四次挥手才能断开。进入FIN_WAIT2状态。再收到FIN报文时表示server端也传输数据结束了,要断开连接。进入TIME_WAIT状态。 在TIME_WAIT状态等待2MSL的时间后进入了CLOSED状态。
服务端握手与挥手
连接
- 收到来自client的连接请求SYN,进入SYN收到状态;发送syn ack,开启定时器 等待接收 ack, 若未收到会 重传, 重传次数 tcp_synack_retries 决定。
- 收到ACK报文,进入ESTABLISHED状态。三次握手结束。
断开
- 收到FIN报文,表示客户端不再发送数据,请求断开,此时进入CLOSE_WAIT状态;
- 自己的数据发送完后发送FIN报文,进入LAST_ACK状态;
- 收到ACK后进入了CLOSED状态。
关于tcp链接的一些说明
2MSL的TIME_WAIT状态
MSL(Maximum Segment Lifetime)是一个报文最大生存时间。为什么是2MSL呢?来自《TCP/IP详解》的解释是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可以让TCP再次发送最后的ACK以防止这个ACK丢失(另一端超时并重发最后一个FIN)。在这期间client的(IP地址:端口号)和server的(IP地址:端口号)均不可以被使用。
连接队列
两个队列:
半链接队列 ;
全链接队列。
当accept收到一个链接会把 全连接队列上的对头 给 取走,如果该队列为空, 会阻塞。
当服务端收到 客户端发来的ack,会将半链接队列的 链接取走 放在 全连接 队列中。如果 全连接队列满了 会根据 tcp_abort_on_overflow 配置执行对应的策略。