工程师进阶:深入TCP协议( 二 )


 
在这之前需要了解一个重要的性能指标 RTT 。该指标表示发送端发送数据到接收到对端数据所需的往返时间 。
建立连接的三次握手

工程师进阶:深入TCP协议

文章插图
 
首先假设主动发起请求的一端称为客户端,被动连接的一端称为服务端 。不管是客户端还是服务端,TCP 连接建立完后都能发送和接收数据,所以 TCP 是一个全双工的协议 。
起初,两端都为 CLOSED 状态 。在通信开始前,双方都会创建 TCB 。服务器创建完 TCB 后便进入 LISTEN 状态,此时开始等待客户端发送数据 。
第一次握手
客户端向服务端发送连接请求报文段 。该报文段中包含自身的数据通讯初始序号 。请求发送后,客户端便进入 SYN-SENT 状态 。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入 SYN-RECEIVED 状态 。
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文 。客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功 。
问题:为什么建立连接需要三次,而不是两次?
因为这是为了防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误 。
可以想象如下场景 。客户端发送了一个连接请求 A,但是因为网络原因造成了超时,这时 TCP 会启动超时重传的机制再次发送一个连接请求 B 。此时请求顺利到达服务端,服务端应答完就建立了请求,然后接收数据后释放了连接 。
假设这时候连接请求 A 在两端关闭后终于抵达了服务端,那么此时服务端会认为客户端又需要建立 TCP 连接,从而应答了该请求并进入 ESTABLISHED 状态 。但是客户端其实是 CLOSED 的状态,那么就会导致服务端一直等待,造成资源的浪费 。
断开链接的四次握手
工程师进阶:深入TCP协议

文章插图
 
TCP 是全双工的,在断开连接时两端都需要发送 FIN 和 ACK 。
第一次握手
若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求 。
第二次握手
B 收到连接释放请求后,会告诉应用层要释放 TCP 链接 。然后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了 。但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A 。
第三次握手
B 如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进入 LAST-ACK 状态 。通过延迟确认的技术(通常有时间限制,否则对方会误认为需要重传),可以将第二次和第三次握手合并,延迟 ACK 包的发送 。
第四次握手
A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态 。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态 。当 B 收到确认应答后,也便进入 CLOSED 状态 。
问题:为什么 A 要进入 TIME-WAIT 状态,等待 2MSL 时间后才进入 CLOSED 状态?
为了保证 B 能收到 A 的确认应答 。若 A 发完确认应答后直接进入 CLOSED 状态,如果确认应答因为网络问题一直没有到达,那么会造成 B 不能正常关闭 。
问题:为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端 。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送 。
ARQ 协议ARQ 协议也就是超时重传机制 。通过确认和超时机制保证了数据的正确送达,ARQ 协议包含停止等待 ARQ 和连续 ARQ 两种协议 。
停止等待 ARQ
正常传输过程
只要 A 向 B 发送一段报文,都要停止发送并启动一个定时器,等待对端回应,在定时器时间内接收到对端应答就取消定时器并发送下一段报文 。
报文丢失或出错
在报文传输的过程中可能会出现丢包 。这时候超过定时器设定的时间就会再次发送丢失的数据直到对端响应,所以需要每次都备份发送的数据 。


推荐阅读