前言
为什么要学习TCP协议?咱也不说什么大道理,简单一句话就是工作需要,当你需要调优一些服务功能以及编写高效的通讯服务的时候就会使用这些知识,所以我就将学习的过程和心得记录下来,方便以后查看以及复习。
一、什么是TCP/IP
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。通过TCP/IP协议架构,更能体现数据传输是需要经过不同协议的。
二、TCP/IP的架构
TCP - 必须掌握从图片可以看出数据的传输从本层到下一层是通过协议进行包装,然后到达下一层,每一层都是由很多协议组成的,TCP/IP协议只是协议族的一员。同处于传输层UDP与TCP区别是什么?
2.1 UDP协议
在网络传输的过程中,发送的数据都会根据协议封装一个数据包。而UDP的数据包由首部和数据两部分组成,首部长度为8个字节,主要包括源端口和目标端口;数据最大为65527个字节,整个数据包的长度最大可达到65535个字节。UDP的数据包如下图:
image.png
从数据包的组成结构可以看出,UDP协议比较简单,实现容易,但它没有确认机制,也就是说数据包一旦发出,无法知道对方是否收到,因此可靠性比较差。
2.2TCP协议
简单来说TCP就是有确认机制的UDP协议,也就是说每一个数据包要求确认,如果有一个数据包丢失,就收不到确认,发送方就必须重发这个数据包,重复接受系统底层已解决。
TCP的报文格式:
image.png
其中比较重要的字段有:
(1)序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
(3)标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
FIN:释放一个连接。
需要注意的是:
不要将确认序号Ack与标志位中的ACK搞混了。确认方Ack=发起方Seq+1,两端配对。
TCP在发送数据之前,必须先建立连接,以保证数据传输的可靠性,也就是经常说的三次握手,而且TCP在断开连接的时候,也不是直接就断开链接的,需要通过四次分手。
三、三次握手和四次分手
三次握手和四次挥手主要是以下三个值的变化:
image.png
3.1 三次握手
通讯过程的图例:
image.png
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
- 客户端想服务端发送一段TCP报文:
- 标记为:SYN,表示“请求建立连接”
- 序号为:seq=X(x默认为1)
客户端进入:SYN-SEN
- 服务端收到来自客户端的TCP报文后,结束LISTEN阶段。并返回一段TCP报文:
- 标记位:SYN、ACK
- 序号:seq=y
- 确认号:Ask = x+1
服务端进入:SYN-RCVD
- 客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
- 标记位:Ask
- 序号为:seq=x+1
- 确认号:ack=y+1
- 客户端进入:ESTABLISHED
服务端收到包后,进入ESTABLISHED阶段,此时双方就能发送数据。
为什么要进行第三次握手?
网络通讯是存在延时或丢包等现象,如果第二次握手成功,但是客户端一直没有收到服务端发送的包,这是客户端就会认为链接没有建立成功,再次进行握手。这时服务端就会产生无效的链接,提高了服务端的开销。
3.2 四次挥手
通讯示例图:
image.png
挥手之前主动释放连接的客户端结束ESTABLISHED阶段。随后开始“四次挥手”:
- 首先客户端想要释放连接,向服务器端发送一段TCP报文:
- 标记位为FIN
- 序号为Seq=U;
- 随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
- 服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:
- 标记位为ACK
- 序号为Seq=V
- 确认号为Ack=U+1
- 随后服务器端开始准备释放服务器端到客户端方向上的连接。
- 客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段
前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了
- 服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:
- 标记位为FIN,ACK
- 序号为Seq=W
- 确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。
- 随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
- 客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:
- 标记位为ACK
- 序号为Seq=U+1
- 确认号为Ack=W+1
- 随后客户端开始在TIME-WAIT阶段等待2MSL
服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。
为什么“握手”是三次,“挥手”却要四次?
释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。
为什么客户端在TIME-WAIT阶段要等2MSL?
为的是确认服务器端是否收到客户端发出的ACK确认报文
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;
否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。
所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因
网友评论