前言
“TCP协议是传输层内两种协议中的一种,数据经过应用层下发到传输层后,必选其一进行数据的封装处理,要么使用TCP协议,要么使用UDP协议。UDP协议是一种无连接的协议,而TCP协议提供的是可靠的面向连接的协议”
TCP
Transmission Control Protocol,传输控制协议,TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议
在发送数据前,通信双方必须在彼此间建立一条“连接”。所谓的连接,其实就是客户端和服务器端确认彼此的发件能力和收件能力的过程,也就是我们所说的TCP的三次握手
三次握手
三次握手的本质是确认通信双方收发数据的能力
如何理解?
假设A是客户端,B是服务器端,A和B如果想用TCP协议通信,那么在通信前,必须确保:
A知道:A有发件能力、A有收件能力、B有发件能力、B有收件能力
B知道:B有发件能力、B有收件能力、A有发件能力、A有收件能力
如何知道?通过三次握手
首先,A给B发送一份信件(SYN_A),B收到了,B就知道:A有发件能力,B有收件能力
然后,B给A发送一份信件,包含B对A的信件(SYN_A)作出的回应(ACK_B),且有一份B的信件(SYN_B)。A收到了,A就知道:A有发件能力,A有收件能力,B有发件能力,B有收件能力
然而,B还不知道:B有发件能力、A有收件能力,所以A给B回复一份信件,包含A对B的信件(SYN_B)作出的回应(ACK_A),B收到后,B就知道:B有发件能力,A有收件能力
这样就通过三次握手确保了通信前A和B必须知道的全部确认。握的是啥?通信双方数据的序列号
客户端和服务端起初都是CLOSED状态,通信开始前,客户端和服务端都要创建各自的传输控制块(TCB)
服务端创建完TCB后进入LISTEN状态,准备接收客户端发来的连接请求
-
第一次握手:客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如是100),那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1),序列号seq=100。同时启动周期性的超时重传,直到收到服务端的应答报文,这是为了防止客户端发送的SYN包丢失而采取的重传机制。另:SYN=1的报文段不能有数据部分payload,但是要消耗一个序号,也就是下次再发送报文,序号+1
-
第二次握手:服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端的起始序列号100存起来,并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。同时启动周期性的超时重传,直到收到客户端的应答报文,这是为了防止服务端发送的SYN+ACK包丢失而采取的重传机制。另:ack是收到的最后一个数据的序列号+1,对端收到数据报后,根据这个ack,明确了两件事:1.我发送的数据报的最后一个数据ack-1已经被成功接收;2.我接下来要发送的数据报的序号要以ack开始
-
第三次握手:客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文;同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始。需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接。服务端只有在超时重传时间内收到第三次握手客户端发送的ACK,服务端才会进入ESTABLISHED状态,只有进入ESTABLISHED,服务端才可以发送数据,双方的连接才算是建立。而客户端只要发送ACK,立刻进入ESTABLISHED状态,即使ACK丢失,客户端并不关心,仍然可以发送数据,因为客户端已经处于ESTABLISHED,格式为ACK+Data。当到达服务端后,虽然服务端处于SYN_RCVD,它依然可以将Data缓存下来,客户端捎带过来的ACK就是对服务端第二次握手的ACK+SYN的又一次确认,这时候服务端立马切换到ESTABLISHED,然后就可以将缓存下来的客户端的Data提交给应用程序
严格来说,三次握手不能叫三次握手,双方确认彼此只需要一次握手就够了,根本不需要握手三次。连握三次手是很神经病的行为
“三次握手”的英文three-way handshake,而不是three handshakes,更准确的翻译应该叫三步握手,是一次握手分三个步骤进行
四次挥手
如果说三次握手的目的是建立一个TCP连接,那么四次挥手的目的就是关闭一个TCP连接
比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据
- 第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),同时启动周期性的超时重传,直到收到服务端的应答报文。释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据。另:FIN报文段即使不携带数据也要占据一个序列号
- 第二次挥手:服务端收到客户端发的FIN报文后给客户端回复确认报文,会通知相应的应用程序,客户端到服务端方向的连接已经释放,同时启动周期性的超时重传,直到收不到客户端的FIN。确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。第二次挥手完成后,客户端到服务端的连接释放,客户端不会发送数据,服务端也不会接收数据,但服务端到客户端的连接仍然存在,服务端可以继续向客户端发送数据
- 第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,同时启动周期性的超时重传,直到收到客户端的应答报文。报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2351(2300+50)
- 第四次挥手:客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2352、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。等待2MSL是为了确保ACK发出后服务端没有重传FIN,报文一来一回的时间大概是2TTL时间。为什么客户端发完ACK后不立刻CLOSED?如果ACK丢失了,服务端会重发FIN,而客户端CLOSED已经无法接收了,那么服务端就会永远无法正常关闭
更多汽车网络诊断通信内容,请关注:汽车网络诊断通信
更多汽车网络诊断通信内容,请关注:汽车网络诊断通信