TCP的三次握手和四次挥手
一、TCP是什么
运输层主要使用以下两种协议:
- 传输控制协议TCP(Transmission Control Protocol)——提供面向连接的、可靠的数据传输服务
- 用户数据报协议UDP(User Datagram Protocol)——提供无连接的、尽最大努力的数据传输服务
TCP是运输层的两种常用协议之一,它是面向连接的,所以应用程序在使用TCP之前,必须先建立TCP连接,在传送数据完毕后,必须释放已经建立的TCP连接。
二、TCP的连接建立(三次握手)
TCP连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户(client),而被动等待连接建立的应用进程叫做服务器(server)。
TCP建立连接的过程叫做握手,握手需要在客户端和服务器之间交换三个TCP报文。(“三次握手” 这个说法是不太准确的,更准确的应该是“三报文握手”)
三报文握手建立TCP连接的过程:
最初两端的TCP都处于CLOSED(关闭)状态,这里假设主机A主动打开连接,B被动打开连接,故A为客户端,B为服务器端。
- 一开始,B的TCP服务器进程创建传输控制块TCB,然后处于LISTEN(收听)状态,等待客户的连接请求。
- A的TCP客户进程创建传输控制块TCB,向B发送连接请求报文,SYN=1,ACK=0,同时选择一个初始序号x(不能携带数据,但消耗一个序号)。TCP客户进程进入SYN-SENT(同步已发送)状态。
- B 收到连接请求报文,如果同意建立连接,则向 A 发送确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y(不能携带数据,但消耗一个序号)。TCP服务进程进入SYN-RCVD(同步收到)状态。
- A 收到 B 的连接确认报文后,还要向 B 发出确认,ACK=1,确认号为 y+1,序号为 x+1(可以携带数据,但如果不携带数据则不消耗序号,即下一个数据报文段的序号仍是x+1)。A进入ESTABLISHED(已建立连接)状态。
- B收到A的确认后,进入ESTABLISHED状态。
为什么A最后还要发送一次确认呢?
主要是为了防止已失效的连接请求报文段突然又传送到了B,让B错误打开连接。
例如,A发出一个连接请求(我们把它叫做一号连接请求),但在某些网络结点长时间滞留了,A等待一个超时重传时间之后,就会重新请求连接(二号连接请求),假设A与B建立了连接,传送完数据后释放了连接。后来,一号连接请求到达了B,就误认为A又发出了一次新的连接请求,于是就向A发送确认。如果不需要发送第三个报文就能建立连接,那么这时新的连接就建立了。 但是现在A并没有发出建立连接的请求,就不会理睬B的确认,也不会向B发送数据。但B却以为新的连接已经建立了,并一直等待A发来数据,这样B的许多资源就浪费了。但是如果采用发送第三个报文的办法,A不会向B的确认发出确认,B由于收不到确认,就知道A并没有要求建立连接。
三、TCP的连接释放(四次挥手)
数据传输结束后,通信的双方都可释放连接
- A发送释放连接报文,FIN=1,序号为u(它等于前面已传送过的数据的最后一个字节的序号加1)(报文段不携带数据,但消耗一个序号)。进入FIN-WAIT-1(终止等待1)状态。
- B 收到之后发出确认,ACK=1,确认号为u+1,序号为v。B进入CLOSE-WAIT(关闭等待)状态。 此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
- A收到B的确认后,就进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。
- 当 B 不再需要连接时,发送连接释放报文,FIN=1,ACK=1,确认号为u+1,序号为w。进入LAST-ACK(最后确认状态)。
- A 收到后发出确认,ACK=1,确认号为w+1,序号为u+1。进入 TIME-WAIT (时间等待)状态,等待 2 MSL(最大报文存活时间)后释放连接。
- B 收到 A 的确认后释放连接。
为什么要四次挥手呢?
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
为什么A在TIME-WAIT状态必须等待2MSL的时间呢?
-
为了保证A发送的最后一个ACK报文段能够到达B。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
-
等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。