目录
1.TCP协议的段格式
2.TCP原理
2.1确认应答
2.2超时重传
3.三次握手(重点)
4.四次挥手
1.TCP协议的段格式
我们先来观察一下TCP协议的段格式图解:
源/目的端口号:标识数据从哪个进程来,到哪个进程去
32位序号/32位确认号:TCP会话的每一端都包含一个32位(bit)的序列号,该序列号被用来跟踪该端发送的数据量。每一个包中都包含序列号,在接收端则通过确认号用来通知发送端数据成功接收
4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节),所以TCP头部最大的长度是15*4=60
6位标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区中把数据读走
RST:要求对方重新连接,我们把携带RST表示的称为复位报文段
SYN:请求建立连接,我们把携带SYN标识的称为同步报文段
FIN:通知对方,本端要关闭了.我们称携带FIN的叫结束报文段
16位校验和:发送端填充,CRC校验,如果接受端校验不通过,则认为数据有问题,这里的校验和不仅仅有TCP首部,也包含的有TCP数据部分
16位紧急指针:标识哪部分数据是紧急数据
40位头部选项和16位窗口大小;我会在后面的博客中详细介绍
2.TCP原理
TCP协议对于数据的管控主要有两个方面:安全和效率
在保证安全的时候,尽可能的提升效率
TCP是如何保证安全的呢,这就要涉及到我们的确认应答机制
2.1确认应答
我们用一张图来描述一下:
TCP协议对每个字节都进行了编号,有与之对应的序列号,当发送数据包到另一端以后,另一端就会确认应答发送应该数据包的最后一位+1,回馈给发送方,发送方下一次就以这个序列号为开始接着发.
2.2超时重传
在数据发送到接收方,没有得到及时响应的时候,就会触发超时重传机制.这也是TCP能保证安全的重要机制.
超时重传有以下两种情况:
1.数据发送给接收端的时候丢包
2.接收端确认应答的时候数据丢包,发送方不清楚数据是否到达,也会触发超时重传
这种情况,接收方会受到重复的数据,所以TCP协议会始别重复的包,并且把多余的给丢弃掉.
这时候我们就可以使用序列号来区分是不是相同的数据,很容易做到去重的效果.
那么这个超时重传的超时,具体时间如何确定呢?
如果时间太长的话,就会影响性能,而时间太短的话,极有可能会造成大量的重复包,造成资源浪费.
TCP协议为了兼顾到这两者,会动态的计算这个最大时间.
在Linux中(windows中也是如此),会以500ms为一个单位去控制,每次判定超时重传的时间都是这个数值的整数倍,如果依旧没有得到应答,就会在2*500ms的时间后再次重传,以此类推,每次都是上一次的两倍,但是如果时间过长又会发生什么呢?
答案是TCP会认为网络出现了问题,强制关闭连接.
3.三次握手(重点)
我们来深入理解,通过画图的方式来生动形象的的描述一下三次握手这个过程.
有的同学可能会有疑惑了,这明明是四次握手,为什么说是三次呢?实际上,第二次和第三次刚好一个在TCP协议格式第二位和第五位,刚好这两个可以一起发送过去,而TCP协议也确实是这样做的.
那么TCP协议的三次握手有什么好处呢?为什么不是两次不是四次,而偏偏是三次?且容我细细道来.
1.可以起到"投石问路"的效果,判断网络是否通畅,这个就像行军打仗的时候,前面的先锋部队会先去前面探路,确定路上没有阻碍了,后面的大部队才会跟着上来.
2.让发送端和接收端都能明白自己和对方的发送接收功能是否是好的.
比如在第一次握手的时候,接收端既然能收到请求就会知道 自己的接收功能莫问题,而发送端的发送功能莫问题
在第二次握手的时候,接收端返回一个应答报文和一个请求连接报文,接收端收到了以后,就知道自己的发送功能和接收功能都没问题.会回给接收端一个应答报文.
第三次握手的时候,接收端收到发送端的应答报文,就明白自己的发送功能和对方的接收功能都是好的.
这样,双方都明白自己和对方的发送功能和接收功能都是否完好.
如果是两次握手,那么就只是在我们上面提到的第二次握手,这样,接收端就不知道自己的发送功能和发送端的接收功能是不是好的,起不到我们想要的效果.
而三次握手已经满足了我们的需求,如果是四次或者多次,虽然也能做到,但是多余了,没有必要在做这么多重复没有意义的工作
4.四次挥手
四次挥手是客户端和服务器端断开连接的一个过程
和三次握手不同的是,四次挥手不仅仅可以是客户端向服务器端发起,服务器端也可以向客户端发起.
三次握手建立连接的本质就是,客户端和服务器端都保存对端的信息,而断开连接则是在数据结构中删除这些信息.我们先用一张图来观察一下四次挥手的过程.
有兄弟可能会问了,凭什么三次握手就可以把中间的两次合并在一起,而四次挥手却不行呢?
这个问题的原因是因为,三次握手的时候,中间服务器确认应答ack和同步报文段syn都是在操作系统内核中完成的,它百分之百都可以同步的完成,所以可以一起发给客户端,
而四次挥手中,ack是在FIN过来以后立刻又内核给返回,而第二个FIN是由代码来完成的,在Java中就是调用了socket.close()方法来完成,如果代码逻辑很长,运行的时间长的话,这两个是不可能同时在一起发送过去,所以这个事并不是百分之百的,尽管有可能合并,但我们通常情况下,把断开连接的这种操作还是称之为四次挥手