1.TCP连接的建立(三次握手、三报文握手)
- 前置准备:一开始客户端和服务端都是CLOSED状态,服务端创建传输控制块TCB,进入LISTEN状态等待客户端的连接请求;客户端创建传输控制块TCB。
- 1)客户端向服务端发送同步报文段,SYN=1,选择一个初始序号seq=x。SYN报文段不能携带数据,但要消耗一个序号。客户端进入SYN-SENT状态
- 2)服务端收到请求后,向客户端发送报文段,SYN=1,ACK=1,确认号ack=x+1,选择一个初始序号seq=y。SYN报文段不能携带数据,也要消耗一个序号。服务端进入SYN-RCVD状态
- 3)客户端收到服务端的确认,再次发送确认报文段,ACK=1,ack=y+1,seq=x+1。客户端进入ESTABLISHED状态,服务端收到客户端的确认后也进入ESTABLISHED状态
为什么是三次?两次可以不?(以下情况假定去掉第三次的确认)
客户端第一次发送连接请求报文段,在某个网络节点长时间滞留,然后客户端第二次发送连接请求报文,这时服务端收到,建立连接,经过一系列的传输后连接释放。过了一段时间后,服务端收到了第一次发送的连接请求,这其实是一个废弃的请求。但是服务端不知道,服务端发送确认后直接建立连接,这时就会浪费资源。
2.TCP连接的释放(四次挥手、四报文挥手)
- 1)客户端发出连接释放报文段,终止控制位FIN=1,序号seq=u,它等于前面已传送的数据的最后一个字节的序号加1。客户端进入FIN-WAIT-1状态。FIN报文段会消耗一个序号。
- 2)服务端收到请求,发出确认报文段,ACK=1,ack=u+1,seq=v,它等于前面已传送的数据的最后一个字节的序号加1。服务端进入CLOSE-WAIT状态。客户端收到服务端的确认后,进入FIN-WAIT-2状态。TCP进入半关闭状态,客户端不会再发送数据;服务端还有数据没有传输完,得继续发送数据,客户端必须接收数据,所以下面的seq=w。
- 3)服务端发出连接释放报文段,FIN=1,seq=w,ACK=1,ack=u+1。服务端进入LAST-ACK状态。
- 4)客户端收到服务端的连接释放报文段后,发出确认。ACK=1,ack=w+1,ack=u+1。客户端进入TIME-WAIT状态。服务端收到客户端的确认后,进入CLOSED状态,客户端等待2MSL(最长报文段寿命)后,进入CLOSED状态。
为什么要等待2MSL?
第一,为了保证客户端发送的最后一个确认报文段到达服务端。
第二,防止下一个新的连接,出现本次旧的连接请求。
建立连接中,客户端出现问题怎么办?
TCP有一个保活计时器,服务端每收到一次客户端的数据,就重新设置保活计时器,时间通常是2小时,超过这个时间没有收到客户端的请求,服务端就发送一个探测报文,每个75秒发送一次,发送10次无响应后,服务端认为客户端出了故障,连接关闭。