网络原理知识(6)

上次我们讲了UDP协议的相关内容,今天我们来讲解TCP协议。

TCP协议

我们之前讲过,TCP的特点是有连接、面向字节流、可靠传输、全双工,还有他的结构:

其中,16位源端口号与16位目的端口号是传输层的核心内容;4位首部长度是以4字节为单位,长度在0到15之间,而选项的存在,导致TCP报头长度是可变的;保留6位,是因为UDP存在长度不够又不能扩展的问题,TCP的设计者就考虑到了,在TCP报头中预留了一些"保留位"(现在暂时不用,先占个位置)。

这些是TCP最核心的6个标志位,而16位检验和是用来校验数据是否出现错误的。

TCP的核心机制

在可靠性中,网络通信是非常复杂的,此处的可靠性,并不是说A给B发一个消息,B100%能收到,而是A给B发了消息之后,尽可能让B收到,并且A能够知道B是否收到。

为了保证可靠性,需要用到这些核心机制,今天肯定是说不完的。

核心机制一:确认应答

保证可靠性的一个关键前提,是发送方知道自己的数据是否被对方收到。

于是需要对方给返回一个"应答报文(ack)",发送方知道应答报文,就可以确认对方是收到了。

正常发送方与接收方的关系:

这里有明显缺陷,如果我连续发多条,可能出现问题。

尤其是上一个图中,出现了数据传输"后发而先至"的问题,为何网络上会出现后发而先至?

就像结婚接亲,男方排出车队,把车开到女方家,只有载着新郎的车(最开始在最前面的请求)才能接新娘,可是这个车队一出村子就走散了,最后先到的不一定是新郎的车。

网络上也是类似的情况,转发数据,每个路由器或交换机,就相当于"十字路口"。

基于此,TCP给了如下的处理方案------给传输的数据进行编号。

于是,在TCP的那张表中,就用了32位序号与32位确认序号。

确认序号只有在应答报文中才能生效,而在ack为1时,表示这个是应答报文。

TCP是面向字节流的,其实在编号的时候,不是按照1条、2条这样的方式来编的,而是按照"字节"来编号的。

其中,每个字节都分配一个编号,这个编号是连续递增的。

这里,一个TCP的载荷是由多个字节构成的,那么在多个编号中,这么多序号该怎么写?

于是,在发送方与接收方之间的传输过程如下:

这里,拿主机A向主机B发送的第一批数据(1~1000)来举例,主机B收到了这些数据之后,他的确认应答有两个作用:

(1)<1001的数据都已经确认收到了

(2)接下来主机A要从1001开始给主机B发送

在引入序号之后,接收方就可以根据序号对数据进行排序。

TCP需要处理后发先至的情况,确保应用程序通过socket api读到的数据顺序是正确的。

即使出现了后发先至,TCP也要处理掉,确保代码里读到的数据(inputstream ,read)和发送方写入的数据(OutputStream,write)顺序一致。

于是就需要进行数据排序,当然,TCP报头不参与编号,序号确认编号都是针对载荷的。

这里TCP在接收方这里会安排"接收缓冲区"(内存,在操作系统内核里),通过网卡读到的数据,先放到接收缓冲区里,后续代码中调用read,也是从接收缓冲区来读的(类似于生产者消费者模型)。

然后根据序号来排序,序号小的在前面,大的在后面,确保前面的数据已经到了,然后read才接触阻塞;如果是后面的数据先到,read继续阻塞,不会读到数据,就像阻塞队列一样。

核心机制二:超时重传

可靠传输,要针对丢包的情况进行处理。

为什么会丢包?

当数据报经过某个路由器、交换机转发的时候,该路由器或交换机已经非常繁忙了,导致当前需要转发的数据量超出了路由器或交换机的转发能力上限。

就像路口上超过最大车流量后堵车一样,数据报会消耗更多的时间才能到达对方,更糟糕的情况是,数据报过多,路由器或交换机根本处理不过来,接收缓冲区都满了,由于网络上的数据报都是有时效性的,于是只能将超出部分丢弃。

这里引入了超时时间来判断是否丢包,TCP中,判定超时时间的时间阈值不是固定的数值,是动态改变的,假设当前A向B发送数据,丢包的超时时间阈值为T,当A给B传输发生超时之后,就会适当延长这个阈值(随着进行重传,导致数据到达对方的概率是越来越高的,重传还不成,说明即使我们增加了概率,还是不能成功,意味着当前丢包概率很大,因此网络上大概率已经出现严重故障了,此时就是继续重传,意义也不大了),会继续延长这个时间,当然,这个延长操作不是无休止的,超时次数达到一定程度/等待时间达到了一定程度,就认为网络出现严重故障,放弃这一次传输。

丢包的情况有两种:

(1)A到B发送的数据丢了

(2)B到A返回的ack丢了

由于发送方A区分不了当前是哪个情况,做法都是进行重传,当然右图还会涉及去重操作。

上述是TCP协议中最核心的两个机制,保证了TCP能够进行可靠传输,但网上说保证TCP可靠传输的关键机制是"三次握手",这个是不对的,这里面试还会考的,具体为什么不准确,我下次再讲。

核心机制三:连接管理

连接管理分为建立连接与断开连接,这个不是抽象的,逻辑上的连接,而是通信双方各自保存对端的信息。

建立连接,通过"三次握手"的方式来完成。

(1)三次握手

握手操作,没有实际的业务,只要发送一个不携带业务的数据,通过这个数据和对方"打个招呼"。

打招呼用syn。

syn就是synchronized,意为"同步的",在TCP中的同步,指的是数据上的同步,即A告诉B:接下来我要和你建立连接,就需要你把我的关键信息保存好,同时你也把你的信息同步发给我。

B收到了A的syn之后,返回syn与ack,表示自己已经收到了A的信息,要A保存B的,最后A向B发ack,表示收到了B的信息。

这里还有一幅图,关于三次握手的详细图:

这里的Listen是启动服务器,new ServerSocket的时候就会进入的状态,意为"服务器准备好了,随时可以有客户端连上来了";中间的两个syn,正常情况下,肉眼看不到这两个状态,当ack之后,这两个状态就会变为Established;而Established是"已经连接了的",客户端和服务器已经建立了连接,接下来就可以传输业务数据了(电话已经拨通,可以说话了)。TCP的状态变化就对应了socket api的情况。

三次握手的流程,是面试的高频问题,是网络中最常考的面试问题,要重点掌握。

当面试到的时候,要画图,画简图,就是那个带AB的。

那么为什么要TCP三次握手,有什么用,解决了什么问题?

1.三次握手,相当于投石问路

先初步的探一探网络的通信链路是否通畅(网络通畅是可靠传输的前提条件)

2.验证通信双方的发送能力和接收能力是否也正常

就像如下例子,两个人一起开黑,验证双方的麦与耳机是否正常:

经过上述讨论,建立连接操作,如果只握手两次,是不够的。因为"师娘"那里仍不知道"我"的接收能力是否正常。

如果握手四次是否可以?可以,但是没必要,因为中间两步合并成了一步。

3.三次握手过程中,可以协商一些关键信息

比如办酒席确定多少桌:

TCP要协商的一个非常关键的信息,是通信过程中序号从几开始(初始序号,一般不是从0开始的),并且,两次连接初始序号都是不同的(往往差别很大)。

第一次的连接建立与断开后,第二次连接建立好之后,已经通信了一段时间之后,刚才第一次连接迷路了的数据包才到达B,此时B一定不要处理这个数据包,因为第二次连接,程序可能不是同一个,此外,即使是同一个程序,之前(第一次连接)已经协商好了初始序号,第二次连接要协商好另一个初始序号,一定与第一次不同,收到的数据和当前连接的数据的序号相差甚远。

(2)四次挥手

A向B发送fin(表示结束与对方的连接),B向A返回ack,表示他已经收到,然后B向A发送要结束与A的连接,最后A要向B返回ack,表示已经收到,四次挥手结束。

三次握手的中间两次都是由内核负责返回的,因此在同一时机,就可以合并;而四次挥手中间的两次如果没有延时应答是不可以合并的(即使有也不一定是同一时机)。

相关推荐
invicinble2 小时前
java面向对象的学习主线
java·开发语言·学习
Devin~Y2 小时前
大厂Java面试实战:Spring Boot/Cloud + Redis/Kafka + K8s + RAG/Agent 追问全流程(小Y翻车记)
java·spring boot·redis·spring cloud·kafka·kubernetes·micrometer
桌面运维家2 小时前
vDisk虚拟磁盘隐藏指定系统操作指南
java·开发语言
被摘下的星星2 小时前
传输控制协议(TCP)
服务器·网络·tcp/ip
Lyyaoo.2 小时前
JWT 令牌(待更新)
java·前端·javascript
knight_9___2 小时前
RAG面试篇8
人工智能·python·面试·agent·rag
jiayong232 小时前
第 40 课:任务详情抽屉里的编辑 / 删除联动强化
java·开发语言·前端·javascript·vue.js·学习
河阿里2 小时前
Java八股:面试高频50
java·面试
positive_zpc2 小时前
计算机网络——运输层
网络·计算机网络