当前位置: 首页 > news >正文

T C P

文章目录

    • 基于UDP应用场景
  • TCP协议
    • TCP 协议段格式
      • 确认应答机制
      • 16位窗口大小 下定义
      • 32位序号和32位确认序号
      • 序号是什么?
      • 确认序号

基于UDP应用场景

UDP,tcp这样的协议根本不是直接谈UDP。tcp的应用场景,一定是上层写了应用层协议,所以才有UDP协议的应用场景。

比如http

TCP协议

传输层最重要的协议,几乎没有之一
因为TCP基于通信时保证可靠性,对于高效传输也有一定策略。
TCP协议是目前应用层协议使用时常见的协议。
比如网络版本计算器,底层是TCP套接字。
http底层就是TCP协议,用的也是TCP套接字。

TCP叫传输控制协议
为什么叫传输控制,从何而来
在这里插入图片描述

TCP在OS内部存在自己的发送和接受缓冲区。
每建立一个链接的的时候,此时OS内部就要为该链接创建发送缓冲区和接受缓冲区

应用层也要定义缓冲区来接受用户输入,和输出结果给用户–用户级缓冲区

计算器为了能接受请求定义string in_buffer
通过read把数据读上来。

当上层调用write,read接口时,本质不是把数据发送到网络中!
那是什么呢?
比如发送,发送的数据拷贝到TCP的发送缓冲区,应用层就认为数据已经交给了系统。
至于数据什么时候发送,发 送多少,出错了怎么办?
完全由OS,TCP协议自主决定

所以write,read,recv ,send与网络相关的发送接口,本质不是发送函数而叫做拷贝函数

好像在哪里听过啊?
以前讲文件的时候不就是这样吗?
往文件里写也用的wirte接口,所以当时说C语言提供缓冲区,也是用户级缓冲区,我们把数据写到文件里,写到OS内部,要通过fd写入的,每个文件都有自己的文件缓冲区,所以应用层读写文件时把数据写到文件里,本质就是把数据拷贝到内核的文件缓冲区里,至于数据什么时候刷,刷多少,整个刷新细节你不用关心,是由OS和磁盘交互的,今天看来磁盘和网络有区别吗?
把磁盘设备换成网卡,不就完成数据发送,IO吗,冯诺依曼体系结构里文件是IO,往网络里写本质不就是在硬件层面上把内存里的数据写到网卡上,也是IO,大家在理念上是一致的,更何况Linux一切接文件。

从今天开始对于网络的理解,就可以这么认为了
我的应用层只负责对收上来的数据进行协议处理,把报文和报文分开,诸如反序列化,变成结构化数据,根据协议对数据做处理,把数据写好的响应发给TCP缓冲区应用层的工作就完了,至于数据什么时候发由TCP决定。

通信双方都支持TCP协议,所以CS的地位是对等的。所以一方学懂了另一方一样。

应用层把数据本质拷贝到发送缓冲区。
至于数据怎么发,其实把传输层发送缓冲区
的数据导到对方的接受缓冲区里,本质也是拷贝!
只不过这个拷贝工作需要通过网络而已,通过网络可能会出错,所以需要很多策略。

接收方通过read调用时会阻塞,由于接受缓冲区没有数据,有数据则资源就绪了。

后面网络和文件揉在一起说说

在这里插入图片描述
解释为什么UDP或Tcp 只有同样一个FD既可以读也可以写,因为一个fd配套两个缓冲区,所以可以即读又写了。-- 全双工

这就是TCP缓冲区的理解。

TCP下层还有协议,我们把数据交给下层,并不是直接发送给对方。

1。传输层的接受缓冲其实就是内存空间
2。OS为了管理对应的内存其实是把整个内存想成一个个4KB空间,所以OS有这么多内存块,OS怎么知道哪些已经被占用了那些没有,那些被锁定了,那些过期了?
OS就要对内存块管理。
为了管理内存所以每个内存块都要有strcut page这样的结构

所以接受发送缓冲区,无非就是多个内存块即strcut page构成的。

OS中用数组把100多万个page管理起来,对内存管理转为对数组的增删查改。

打开一个网络相当于得到一个文件描述符,底层一定有Strcut file对象,Strcut file对象以前指向磁盘,今天网络Strcut file对象指向网络设备,每个Strcut file后面跟上两个缓冲区,由多个4kb构成的,此时上层不变下层直接切换成网络这样的效果。

为什么突然扯到这里呢?
问题
所以为什么叫传输(能理解)控制协议(能理解)?
控制是什么意思?
应用层把数据经过write拷贝到发送缓冲区里,至于发送缓冲区里的数据什么时候发,发多少,本质就是在控制如何发送的问题。
这些工作由TCP协议自主决定,所以把他叫做传输控制协议。

为什么提供发送缓冲区呢?
当前对端来不及接受了,发送端怎么知道呢?用户一直把数据往缓冲区写,因为有缓冲区的存在,即便来不及接受了,但对于应用层来讲,可能并不影响应用层继续向OS拷贝,数据拷贝多了,发送缓冲快满了,OS就让对方接受缓冲区快点拿数据了。

TCP是具有接受发送缓冲区,进行全双工通信的,进行数据发送控制的一种协议。

TCP 协议段格式

应用层 请求和响应
传输层 数据段
网络层 数据报
链路层 数据帧

问题
1、报头和有效载荷如何分离,如何交付给上层?

TCP协议基本结构分三部分
TCP报头前20字节就是TCP标准报头
TCP支持对应的选项–我们忽略但存在
第三部分,TCP协议的有效载荷
在这里插入图片描述

如何交付给上层?
前两个字段,端口交付给上层目标进程
在这里插入图片描述
对TCP报文向上交付给进程
一行是4字节,0-31
标准报头一共五行,所以标准报头是4x5=20字节

报头和有效载荷如何分离?

当读取TCP数据时,在缓冲区里把前20字节拿出来,报头信息全拿到了,标准报头全拿到了他也是约定长度。
TCP报文里有一个字段,4位首部长度
凡是报文里介绍首部长度,他就真的是。
表示报头总长度,你不是说了标准报头是20字节吗,因为还包含了选项,选项也可以不带。
4位首部长度 【0000,1111】【0-15】
全写成1表示数字也就是15,怎么可能是20 呢?
是不是有问题呢?
不是,因为4位首部长度计算的时候,有基本的大小单位:4字节
则表示长度范围【0,60字节】
所以选项最多是40字节。

如果不带选项,则四位首部长度设为X
x * 4 = 20 => x = 5 = 0101

4位首部长度准确的把报头从整个报文里去掉

报头和有效载荷如何分离我们怎么做呢
实际上先读取前20字节,固定长度,之后根据4位首部长度计算出实际总大小再减去20剩下的就是选项的大小,没有的就不读了,剩下的就是数据
所以如何分离?
固定长度(前20字节)+ 自描述字段

你收到一个数据能不能按照指定字节数对数据做截取呢?
你直接把数据收上来,截取前20字节,整个报文也是结构体,地址强转成结构体指针直接从里面提取4位首部长度,这个4位长度描述是自身的报头大小,所以他叫自描述字段。(我们网络版本计算也带有有效载荷长度,也叫做自描述字段)
固定长度+自描述 的方式 能把标准报头和选项全部读上去,因为标准报头就是20字节,剩下的就是数据,所以能作分离。

1、报头和有效载荷如何分离,如何交付给上层?
搞定
在这里插入图片描述

整个报文也是结构体,他所谓的封装是把报头结构体变量形成的对象内容拷贝到数据前面。
能封装,也能拆开

下一个问题
16位窗口大小

左边客户端,有应用层和传输层/TCP
TCP有自己的接受缓冲区和发送缓冲区。
对于服务端也是这个结构
此时应用层构建Http请求
把数据通过write结构写到发送缓冲区里,传输层要发送这个数据给对方,此时要给发送的数据添加TCP报头
在这里插入图片描述
没来得及发送的就放到发送缓冲区里,可能有多个Http请求
在这里插入图片描述

封装报头经过底层交到对方的接受缓冲区里时,对方收到这个报文要进行报头有效载荷分离,套接字创建出来都要有自己的接收缓冲区,至此去掉报头的Http有效载荷请求放到接受缓冲区中。
在这里插入图片描述

问题
你心里要特别清楚,客户端和服务器基于tcp协议进行通信时,互发消息的时候,发送的可是完整的tcp报文哦,即一定携带完整的tcp报头
不管课件如何简写,双方通信时发数据发确认,当你看到数据时可不仅仅是数据他一定要涵盖tcp报头+数据,响应同理
在这里插入图片描述

看起来是发syn+ack,本质上是把报头特定的属性字段设置了,归根结底所有请求和响应都要基于tcp报头为载体
在这里插入图片描述
发起Http请求时一定要想到请求包含报头一大堆东西的。
tcp一样,报头必须完整

换句话说,C给S发消息时基于套接字,上层来看都是通过fd来读写的。
所以你打开多个套接字建立多个连接每个连接都要有一对收发缓冲区

双方通信时发送的报文携带完整报头

tcp协议要保证可靠性
不可靠的表现呢?
数据传输出现重复,乱序,丢包
发送的过程本质是把数据拷贝给对方,对方接受缓冲区是固定大小的,所以他的剩余空间就少了,如果应用层就不想读,此时发送方应用层给对方一直发消息,客户端和服务器双方进行通信时,客户端不清楚服务器接受能力的,所以客户端一直给服务器发消息时,服务器来不及接受,最终可能导致服务器接受缓冲区被写满,客户端又不知道就继续发,最后导致接受缓冲区没空间导致数据丢包。
所以CS通信时,服务器接受能力很少的时候我们要让客户端发慢点或者干脆不发了,
由发送方向服务端发消息,通过控制发送数据的速度让对方来得及接受从而规避大面积丢包的情况,我们称为流量控制
在这里插入图片描述

tcp注定要解决这个问题
tcp可靠性里有一种叫做丢包重传
如果报文丢失了,发送发可以对服务器补发的。
如果对方来不及接受了出现大面积丢包,tcp害不害怕丢包,不害怕他有重传啊。
可以吗这样,可以。

但有更好的方案啊。
虽然你有重传,但是这样不合理,报文经过千里迢迢到了对端,我没有明显错误却要把我丢弃掉,所以他不合理。
我们不能让他启用重传策略,浪费曾经的发送,效率必定不高

既然来不及接受,那就要发送慢一点

tcp保证可靠性,凭什么说他保证可靠性?
最基本的一个特点:确认应答(最重要的机制)

比如我们两个相隔千里,老师说的话同学听到没听懂没老师不知道,所以老师经常说听懂没,听懂扣1,要求你给我响应的过程就叫做确认应答

所以暂时认为客户端给服务器发送任何消息的时候,服务器都要对收到的消息进行响应

那你能保证你扣的6,老师一定能看到吗

确认应答机制

CS双方地位对等
在这里插入图片描述

如果C给S发消息,即便服务器没有任何话说,但服务器至少要对消息进行一次确认应答。
服务器想给客户端发消息,客户端OS也要立即给服务器确认应答。

这样就能保证对于C来讲,客户端刚刚发的消息服务器收到了。
基于确认应答保证了客户端到服务器方向的可靠性
同理服务器给客户端发消息,客户端做应答保证服务器到客户端方向数据的可靠性

重谈通信过程

客户端向发送消息交给服务器,服务器收到了这个消息,TCP协议要立即给对方应答
在这里插入图片描述
问题
无论发送消息,确认应答最后都是tcp报文,无论发的是什么消息什么应答,一定携带完整的tcp报文或者是报头

在这里插入图片描述
发送方 发送的量非常大,也很快
导致对方来不及接受,所以需要流量控制,无非就是让客户端发送数据慢一点,要发慢一点依据是什么?慢多少啊?
靠谁来决定呢?
由对方接受缓冲区当中剩余空间的大小决定

对于发送方来讲,发送速度由对方的接受缓冲区中剩余空间的大小决定!!!

剩多少空间让我知道了,我就可以根据你剩余空间最多发送把你缓冲区打满的数据,发满了我就不发了。

关键在于,客户端是给你发送数据,客户端怎么知道你服务器端剩余空间的大小呢?

我们tcp基于确认应答机制的,你发了一个报文我要给你响应,别忘了请求和响应都要是完整的报文,所以发一个消息对方会给我响应的,我收到响应才发 第二个目前认为。
收响应的时候,我就收到来自服务器给客户端发来的响应,响应中16位窗口大小填充就是我服务端接受缓冲区剩余空间大小。
得知对方接受能力是多少,客户端就知道应该最多发多少数据了。
这就叫16位窗口大小。

16位窗口大小填的应该是谁的接受缓冲区剩余空间大小呢?
客户端给服务器发,要进行流量控制,服务器有没有可能给客户端发消息呢?
tcp是全双工的。
所以从客户端到服务器端要进行流量控制,那么从服务器到客户端发送要不要也进行流量控制呢?

所以双方互发消息,互相确认应答,双方会出现很多tcp报头往来,双方根据报头里16位窗口大小,互相得知对方的接受缓冲区剩余空间大小,双方就可以进行互相流量控制。

16位窗口大小 下定义

我要填充的报头一定是我要给对方发的。
所以16位窗口填写的是自己的接受缓冲区中剩余空间的大小!!

这么多报头传输效率会不会很低?
后面有滑动窗口

(应用层比如Http有主从关系,你是客户端你只能向服务器发起请求
tcp双方地位对等,即你能向我发送报文我给你确认应答,左侧右侧都要互相有流量控制。

32位序号和32位确认序号

tcp说自己有确认应答机制,我们该如何理解确认应答呢?
为什么确认应答是保证可靠性最重要的一个核心点呢?

思考一个问题
这个世界,存不存在100%可靠的网络协议?

例子,我跟你不是面对面,相隔100米
我给你发了个消息,我们去吃饭吧
你回了个好的,这样能保证我给你的消息你是收到了的,但是你怎么知道刚刚说的好的被我收到了呢?

那我要保证你刚刚给我发来的好的消息,我也想让你知道我已经收到了,怎么办呢?我再给你回收到了你的好的了
在这里插入图片描述
可是当我给对方发了收到了你的好的了,确实能保证上一次的好的消息被我收到了,可是最新的消息怎么保证对方也收到了呢?那对方再给你个应答吧, 最新的消息怎么保证对方一定收到了呢?
在这里插入图片描述
1。站在我个人角度只要我收到应答,我就能保证我最近一次发送的消息对方收到了。
同理对对方也一样

2。没有应答的数据,我们无法保证可靠性,所以最新的一条消息,不管是我给对方说,还是对方给我说永远存在最新的一条消息,是没有应答的,所以在人类世界里几乎无法保证发出的消息时100%可靠的!

在这里插入图片描述
所以世界上不存在100%可靠的协议的

虽然整体不存在,但是局部上呢?

我刚给你发的消息,我给你应答,对你来讲,你并不确定这个应答我是否收到,对我来讲我只要收到对应的应答,我能保证从左向右方向上数据的可靠性。
在这里插入图片描述
对右边来讲,右边给左边发的消息只要右边也收到应答,他无法保证 最新的消息被自己收到,但只要右边收到了应答,就能保证从右向左的可靠性
在这里插入图片描述
虽然最新的一条消息没有应答,无法保证最新的一条消息可靠,但是局部上最新消息之前的消息我们其实是可以保证双方在两个方向上的可靠性。

这样说有点抽象,直接说tcp真实的方案

左C,右S
tcp最基本,最原始的通信过程
所以刚刚场景中,除了最新的消息,上面之前每一个报文的都有应答
所以之前的消息能保证各个方向上的可靠性
正常情况不会存在这样的场景的
我给你发个消息,你给我应答了,收到了,站在我的角度呢我就不再给你发消息了。
我们没必要对应答再作应答,实际上是鸡生蛋,蛋生鸡的问题,无穷尽了。

CS通信最终要的是保证两个方向上的可靠性
所以C给S发一条消息,tcp数据
S要合适的时候对消息进行应答,因为是客户端给服务器发消息,我要保证消息被对方收到了,我是主动的对方被动,我只要保证我发的消息被对方收到了,这不就达到了宏观层面上我们两个通信的目的吗。
所以我给对方发消息,对方只要给我应答,我收到应答时能保证我发的消息被对方收到了,这就叫保证客户端到服务器方向上的可靠性。
我们不需要再对应答再给S进行响应。
在这里插入图片描述
如果服务器要给客户端发消息tcp数据本质也是完整的tcp报文。
服务器是主动的一方,他要给客户端发消息,本质的目的就是想确认把这个数据发送给C,包括C给我做应答,你也是告诉对方你刚给我发的消息我已经收到了。
所以C也给S发了个应答

在这里插入图片描述

虽然C不能确定应答有没有被S收到,暂时我们不管,但假设S收到了应答,服务器立马就意识到我刚刚发的消息对方也收到了,所以只要收到应答,我们从右向左的可靠性也能保证。
在这里插入图片描述
所以要发送的一个数据,对应配套的收到应答,就能保证两个朝向上的可靠性。

所以第一阶段总结论
CS基于tcp通信时,我发的消息你给我应答,服务器给应答就行了,假如客户端收到这个应答,我就能保证从左向右的可靠性

最终所以工作都是围绕着发送的tcp数据是否被对方收到
在这里插入图片描述
1。S收没收到他自己清楚
2。只要C知道发送成功了,C就不管了,发送失败还有其他策略。

所以确认应答机制本质是使用了对应的局部上只要收到了我们收到了应答就能保证历史消息被对方收到这样的结论

有人就想到了,那要是应答丢了呢?
我作为C给S发消息,S给我进行应答,万一应答丢了呢?
站在C角度不就是他发出去的消息没有应答吗,此时已经是对应的答案了。没有应答客户端就认为对方没收到,所以进一步重发就可以了。这里其实有个问题,C给S发消息,S给C发应答,C怎么知道自己没有收到应答呢?
因为我们应答是由S响应回来的,没有收到应答前客户端连自己发出去的数据是不是丢失客户端都不确定,所以C确认自己有没有收到应答呢,C不是一直要等,万一数据丢了永远不会有应答,所以对C来讲怎么保证有没有收到应答?
C会进行一段时间,如果没有收到应答,C认为数据丢失了,此时重传就可以了。

作为C来讲,C要给S发消息,所以最重要的事情是保证C给S的消息被S收到了,S有没有收到消息他自己最清楚,最重大的问题是C不知道自己有没有被S收到,所以原则上只有C给S发过去的消息,S给了应答就认为我给对方发的消息对方收到了,所以保证从左向右的可靠性,从右向左一样。

所以我在把消息发出去的时候,在我没有收到应答之前,实际上对应的发送方要把数据暂时的维持一段时间,当我收到应答才把这个数据去掉。
这里有涉及滑动窗口后面说。

所以tcp保证可靠性,只要我收到了应答我能保证我刚发的消息对方一定收到了。
同样的对方给我发消息,我也会给对方做应答
通信不就是这样吗,我要可靠的把我的消息发给你,你要可靠的把消息发给我,现在目的达到了吗?
达到了,只有我收到应答就行了,没有应答就丢了。

细节
1我们一起去吃饭吧

2好的
2吃什么呢?

1饺子吧
1可不可以呢?

2 好的

我们会不会这样沟通呢?
很少
我们应该是
1我们吃饭吧
2吃什么啊
3饺子

2吃什么啊
这句话本身是既带确认,又挟带了对方想给我发的消息

所以我给对方发消息,对方给我应答,对方可能也想给我发消息,我给对方应答。
这种通信方案比如下图
让S响应 应答 S后面还发了报文,此时是发了两个报文的
在这里插入图片描述
不要忘记了,每一个报文都是一个完整的tcp报头,虽然标记位一个都没学,但是图中发两次这种方式比较低效率。
所以C给S发消息,S说好的,S可能也要给客户端发消息,所以此时可以把两个消息应答+我要给对方发的消息二合一,形成一个对应的响应,既是对客户端的响应,又是服务器想给C发消息,这种策略叫做 捎带应答

在这里插入图片描述
C也可以采用同样的策略,我们两个实际通信时纯粹的应答可能会比较少,双方通信时还是你来我往的。
这就叫做可靠性这是第一个。
虽然应答可能丢失,经过是否收到应答,就能评判刚刚发的消息对方是否收到,这是最重要的。

这其实是tcp最原始的通信过程
这样是可以的
但是如果客户端要给S发很多消息,如果S还没有给我应答的时候,我的C能不能发第二条消息,我发第二条消息客户端还没应答时,能不能发第三条消息?
从最原始的通信过程来看,我们收到应答才发第二条消息。
对于发送方来讲,发送数据的过程全部都是串行的,发一个消息得到应答才能发下一个,这样tcp通信效率非常低下。

C给S发消息的本质最终我只是要把一批消息被服务器全收到,只要客户端能收到各个数据应答就行了。
所以主流tcp并不是这种发一个应答一个,这样效率太低。
客户端可能会向服务器一次发一批消息,之后呢,服务器原则上针对每一条消息进行应答,只要客户端收到了历史上发过去每一个报文的应答,虽然我们是并行一次发了大量数据,但只要每一个都有应答,我们照样可以保证客户端向服务器方向上的可靠性,只要我收到应答就行了。
在这里插入图片描述

这是tcp比较常规的工作方式
那我一次发多少呢?万一中间出现丢包怎么办?
先暂时不管,后面说。

现在的问题就是C存在给S发送很多报文,每一个报文都是挟带报头和数据的信息发过去了。
客户端发过去的消息按顺序发出,S是否一定按顺序接受呢?
不一定!
就像你们班全去旅游,出发顺序和到达顺序不一定一样,今天同样受网络影响。
所以S收到的本质是把数据放到接受缓冲区里,收到的消息可能并不是我们曾经发送的顺序,这种情况叫做数据包乱序问题。

在这里插入图片描述

如果我们不管这个问题,直接把数据(图里黑色乱序上边一堆圈圈)交到接受缓冲区里,最后直接按乱序交给应用层会带来什么后果呢?
应用层解析请求全都是乱的。
所以乱序本身就是不可靠的一种。
所以怎么保证对应的可靠性呢?不乱序呢?
首先数据包按顺序到达对于S来讲是不保证的,因为网络路由网络路径可能有差别,可能刚发出去第一个路由器就坏了。
所以每一个tcp报头里会包含序号的东西。
给第一个报文带1,第二个带2,但事实不是这样的。
在这里插入图片描述

只要序号给对方发过去了,到了服务端收到乱序也没关系,我们可以根据序号对收到的报文进行排序就可以保证可靠性。

序号的核心作用之一叫做 保证数据的按序到达
可是你说的序号是什么意思呢?
确认序号又是什么鬼呢?

序号是什么?

不着急,同学们,慢慢的它把答案揭晓出来
只有慢慢的把前因后果交代清楚,很多东西才有逻辑,凡是被理解的东西才可能记忆深刻。

横向上 用户层
下层 tcp发送缓冲区

我们对于tcp发送缓冲区的理解,我们可以把它想象成chat outbuffer[N]

tcp面向字节流,所以tcp把缓冲区看出char类型的大数组,所以用户层拷贝下来的任何数据说白了不就是一堆二进制或者叫做char类型数据,我按八个bit位为单位。
所以你自己拷贝下来的数据其实在缓冲区里是按顺序存在的。

在这里插入图片描述

我们上层拷贝下来的数据在缓冲区里按照一个字节一个字节存在的。
不要说你上层是Http,Http在我看来就是一个大字符串,只不是按\r\n区分行的,都是字符,哪怕是二进制的在我看来都是按字节为单位陈列的。

你不是面向字节流吗缓冲区,比如Http请求就有可能如此陈列
在这里插入图片描述
意思就是上层拷贝下来的所有内容就按字节方式全部读走了,然后我们对应的,假设今天第一个tcp报文给对方发送若干字节,
当我把上层数据拷贝到发送缓冲区里,其实我把他当成char类型数组时,其中接受缓冲区里每一个字节都有天然的编号(本质就是数组下标)
在这里插入图片描述
假设我今天要发送的数据块,因为我可能发送不是一个字节一个字节发的,我一次发一批。当我把这批想发出去的时候,整个这个报文将来被封装的时候,他所填充的序号就是最后一个报文所对应的下标数字,就称为它的序号
在这里插入图片描述
所以发送数据的本质就是把缓冲区里的数据从左向右依次发送到网络里,从左向右的过程每次发送对应的一堆数据,每个数据块对应的序号我们都是以最后一个字符为准的话,他就叫对应的序号了。

在这里插入图片描述
课件上第一个报文序号应该是1000后面说
在这里插入图片描述
数组本身下标是连续的,当我收到报文之后就能根据序号进行排序就可以了。
在这里插入图片描述
这样就能保证按序到达了。

那万一丢包了呢?
我怎么知道是哪些报文被对方收到了呢?
以及确认序号是什么意思呢?

问题是我怎么知道响应是对哪个报文的响应?

确认序号

填充的是,收到报文的序号+1
在这里插入图片描述

这是他的约定

为啥要这么规定啊?

确认序号的意义:表示确认序号之前的数据,我已经全部收到了!

也就是1001之前的数据我全都收到了

下次发送,请从确认序号指定的数字开始发送!
发一个1000,给你响应1001,对于客户端来讲,读到应答
1。他能确认自己刚刚发的1000序号的报文对方收到了。他能保证这个应答就是给他的
2。1001表明1001之前的所有数据服务器全收到了。
3。客户端在发送就应该从1001开始继续发下一个报文。

为什么规定序号值1000还要+1呢?
因为假设应答丢了,1001,2001丢了,但是3001却收到了。
你发送了大量数据,我给你响应3001,此时我们不管1001,2001了我们认为3001服务器已经报3001之前的数据全部收到了,通过这样的规定,我们允许应答有少量的丢失

教材写的是1001-2000 实际上就是2000
在这里插入图片描述
问题
不管请求还是应答本质都是tcp报文,只不过应答不需要带数据,请求带数据

我给对方发了一个数据请求,我用序号,服务端给对方应答的时候它直接复用序号位就行了,我用一个序号,比如你给我序号1000,我还用这个序号加1,在写回去,然后把这个报文返回给你,此时我用一个序号就可以了,就完成了请求和应答的过程
我为什么要搞两个一个序号,一个确认序号呢?
应答的时候又没有数据,那你直接把序号复用就行了啊,我们约定用一个序号就行了啊
为什么非得在报头里看到两个序号呢

原因在于
两个场景理解他的
1。客户端给服务器发消息,服务器给我应答同时也可能想给我发消息,所以他也可能挟带数据,对于服务器来讲基于捎带应答既是应答也是数据,对于S给C响应应答此时使用确认序号,它本身也携带数据需要由客户端对它做响应,所以他就使用序号。
任何报文可能有双重身份,所以序号和确认序号可能同事存在,所以协议里必须把两个序号分开,不能复用。

2。通信时,CS地位是对等的,所以互发消息的情况很常见,CS互发消息,所以序号的问题还是分开。

所以就有两个序号。

问题
应答的确认序号,为什么要填充收到的报文+1?
这是一个规定
发个序号1000,你应答1001
我能确定应答是对1000的应答,因为1001-1就是1000
所以1000报文被对方收到了

另外1001之前的数据对方全收到了。
此时允许应答有部分丢失

理由不充分
快重传再聊

保留6位,16位检验和 不谈
选项不谈
在这里插入图片描述

tcp协议中携带了6个标记位

实际上S会收到来自多个C的请求

因为S和C 比重 1:n

tcp 通信时,建立连接
正常的数据通信
tcp通信完了,断开连接
在这里插入图片描述
建立连接要三次握手,断开连接要四次挥手
tcp建立连接的时候,我虽然不懂C和S怎么建立连接的,但我知道你一定要发送tcp的报文,包括接下来正常的数据通信时,和断开连接时。

在这里插入图片描述
所谓的三次握手不就是C和S来回三次通信,只要进行通信,你一定要互相发送完整的TCP报文。至少要有报头可以没有数据。
不管你建立连接还是正常通信还是断开连接,你们都是要发送tcp报文的。

所以呢?

所以通信之前呢我们有些tcp请求是用来建立连接的,有的是把数据交给服务器的,有的功能性是用来断开连接的,这就注定了服务器收到了tcp的报文本身是有类型的。
不同的类型,决定了S要做不同的动作!

例如
如果你发了建立连接的请求,S应该要和你进行三次握手的动作,而不是正常的发送数据,如果你发的是断开连接的请求,我就要
四次挥手,并且断开连接的过程,如果是正常的数据通信,我才把收到的报文进行报头和有效载荷分离,然后把收到的报文放到tcp的接受缓冲区里然后交付上层。
在这里插入图片描述

所以不同的报文类型决定了服务器要做不同的动作。
问题是我们的C和S双方通信时,一定是互相发送的是完整的tcp报文
建立连接和断开连接可能只含有tcp的标准报头,正常通信时可能有数据
在这里插入图片描述

所以问题是
接收方,如何得知,报头的类型各自是什么呢?

所以我们需要tcp里存在6个标记位

标志位存在的意义:区分tcp报文的类型!!!

下一篇
我们进入六个标记位
和tcp的具体可靠性和效率的策略如何保证。

UDP报文。
报头是定长的,UDP报头里有个UDP长度能算出有效载荷长度
可是tcp协议里只有报头长度,他没有有效载荷长度,不知道你发现没?
因为它是面向字节流的后面说。

那接收方咋知道有效载荷多长?
对方为什么要知道啊,对方不需要知道,tcp保证可靠性你一直发我就一直收,字节流,不像udp,字节流我不需要知道长度,你不发你就关了,关了读到0我就认为你完了,我tcp协议不对报文做任何解释,你带了长度报文和报文之间不就有间隔了吗,对我来讲不是,你给我发的数据,你发了多少我放多少,原封不动放到缓冲区里。
这就叫做字节流。

所以网络版本计算器为什么读取时,要先读取len\r然后再读取有效载荷,因为它是面向字节流的,他的报文之间没有边界,后面我们会谈数据包粘包问题,到时候就知道字节流是何意了。

发送缓冲区有没有可能缓冲区不够了,发送缓冲区和接受缓冲区实际上是环状的。

序号是循环的吗,还是一直增大?
序号是一直增大的,达到一定程度会回绕的,回绕数字非常大,一般出现不会冲突。

相关文章:

T C P

文章目录 基于UDP应用场景 TCP协议TCP 协议段格式确认应答机制16位窗口大小 下定义32位序号和32位确认序号序号是什么?确认序号 基于UDP应用场景 UDP,tcp这样的协议根本不是直接谈UDP。tcp的应用场景,一定是上层写了应用层协议,所…...

MongoDB的简单使用

MongoDB(文档数据库)的简单使用 MongoDB最好的学习资料就是他的官方文档:SQL 到 MongoDB 的映射图表 - MongoDB 手册 v8.0 1.MongoDB CRUD操作 1.1Insert操作 基本方法: db.collection.insertOne() 将单个文档(document)插入集合中 db.collectio…...

【Exp】# Microsoft Visual C++ Redistributable 各版本下载地址

Microsoft官方页面 https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads Redistributable 2019 X86: https://aka.ms/vs/16/release/VC_redist.x86.exe X64: https://aka.ms/vs/16/release/VC_redist.x64.exe Redistributable 201…...

【MySQL】表的约束

目录 一、非空约束not null 二、默认值约束default 三、列描述comment 四、填充零zerofill 五、主键primary key 六、自增长auto_increment 七、唯一键unique 八、外键foreign key 一、非空约束not null 如果不对一个字段做非空约束,则默认为空。但空数据无…...

c++高级篇(四) ——Linux下IO多路复用之epoll模型

IO多路复用 —— epoll 前言 在之前我们就已经介绍过了select和poll,在作为io多路复用的最后一个的epoll,我们来总结一下它们之间的区别: a select 实现原理 select 通过一个文件描述符集合(fd_set)来工作,该集合可以包含需要监控的文件…...

基于Java Springboot环境保护生活App且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 微信…...

.NET 9 中 LINQ 新增功能实现过程

本文介绍了.NET 9中LINQ新增功能,包括CountBy、AggregateBy和Index方法,并提供了相关代码示例和输出结果,感兴趣的朋友跟随我一起看看吧 LINQ 介绍 语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称。 数据查询历来都表示为简单的…...

【Vue3中Router使用】

Vue3中Router使用 1. 安装vue-router组件2. 建两个测试页面2.1 测试页面Home.vue2.2 测试页面Category.vue 3. 创建路由对象4. 在入口main.js中引入router把App.vue改成路由页面5. 测试5.1 关闭检查解决ESlint报错5.2 改文件名解决ESlint检查报错测试WebHashHistory 和WebHisto…...

性能测试攻略(一):需求分析

性能测试成为软件开发和运维过程中不可或缺的一环。性能测试不仅能够帮助我们了解系统在特定条件下的表现,还能帮助我们发现并解决潜在的性能问题。那么我们怎么做一次完整的性能测试呢?首先,我们需要进行需求分析,来明确我们的测…...

android WebRtc 无法推流以及拉流有视频无声音问题

最近在开发使用WebRtc进行视频通话和语音通话,我使用的设备是MTK的手机,期间后台的技术人员几乎没法提供任何帮助,只有接口和测试的web端,有遇到不能推流。推流成功网页端有画面有声音,但是安卓端有画面,没…...

Socket编程TCP

【Linux】TCP编程 实验&#xff1a;通过TCP通信—在客户端输入要执行的指令&#xff0c;接收执行结果&#xff0c;另服务端接收指令并执行&#xff0c;向客户端发送执行结果 //主函数 #include<iostream> #include<string> #include"log.hpp" #include…...

《以 C++为笔,绘就手势识别人机交互新画卷》

在科技浪潮汹涌澎湃的当下&#xff0c;人机交互领域正处于深刻变革的前沿阵地。从古老的命令行输入到图形化界面的鼠标点击&#xff0c;再到如今风靡全球的触摸操控&#xff0c;每一次交互方式的革新都重塑了我们与电子设备的沟通模式。而近年来&#xff0c;手势识别技术作为一…...

【CSS】小球旋转loading加载动画

效果 css小球旋转loading动画 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document<…...

Leetcode经典题6--买卖股票的最佳时机

买卖股票的最佳时机 题目描述&#xff1a; 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。…...

BA是什么?

目录 1.EKF的步骤 一、问题定义与模型建立 二、线性化处理 三、应用卡尔曼滤波 四、迭代与收敛 五、结果评估与优化 注意事项 2.BA问题的步骤 一、问题定义与数据准备 二、构建优化模型 三、选择优化算法 四、执行优化过程 五、结果评估与优化 六、应用与验证 1.…...

【IDEA】报错:Try to run Maven import with -U flag (force update snapshots)

问题 IDEA运行项目报错&#xff1a;Try to run Maven import with -U flag (force update snapshots) 原因 IDEA 的项目运行绑定的maven有问题&#xff0c; 解决问题 检查项目绑定的maven配置...

MATLAB提供的窗函数

加窗法 为什么使用加窗法&#xff1f; 在数字滤波器设计和频谱估计中&#xff0c;加窗函数的选择对于整体结果的质量有重大影响。加窗的主要作用是减弱因无穷级数截断而产生的吉布斯现象的影响。 windowDesigner 六种常见的窗函数 根据离散时间傅里叶变换的乘法性质&a…...

git 使用配置

新拿到机器想配置git 获取代码权限&#xff0c;需要的配置方法 1. git 配置用户名和邮箱 git config --global user.name xxxgit config --global user.email xxemail.com 2. 生成ssh key ssh-keygen -t rsa -C "xxemail.com" 3. 获取ssh key cat ~/.ssh/id_rsa.…...

【深度学习】深入解析长短期记忆网络(LSTMs)

长短期记忆网络&#xff08;Long Short-Term Memory networks, LSTMs&#xff09;是一种特殊的递归神经网络&#xff08;RNN&#xff09;&#xff0c;专门设计用来解决标准 RNN 在处理长序列数据时的梯度消失和梯度爆炸问题。LSTMs 在许多序列数据任务中表现出色&#xff0c;如…...

vue watch和computed的区别,computed和method的区别

发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 在 Vue 中&#xff0c;watch、computed 和 methods 都是常用的响应式功能&#xff0c;它们的用途和工作方式有所不同。下面分别解…...

搭建高可用负载均衡系统:Nginx 与云服务的最佳实践

搭建高可用负载均衡系统&#xff1a;Nginx 与云服务的最佳实践 引言 在项目开发过程中&#xff0c;我们通常在开发和测试阶段采用单机架构进行开发和测试。这是因为在这个阶段&#xff0c;系统的主要目的是功能实现和验证&#xff0c;单机架构足以满足开发人员的日常需求&…...

FFmpeg 4.3 音视频-多路H265监控录放C++开发十九,ffmpeg复用

封装就是将 一个h264&#xff0c;和一个aac文件重新封装成一个mp4文件。 这里我们的h264 和 aac都是来源于另一个mp4文件&#xff0c;也就是说&#xff0c;我们会将 in.mp4文件解封装成一路videoavstream 和 一路 audioavstream&#xff0c;然后 将这两路的 avstream 合并成一…...

Node.js JWT认证教程

Node.js JWT认证教程 1. 项目介绍 JSON Web Token (JWT) 是一种安全的跨域身份验证解决方案&#xff0c;在现代Web应用中广泛使用。本教程将详细讲解如何在Node.js中实现JWT认证。 2. 项目准备 2.1 初始化项目 # 创建项目目录 mkdir nodejs-jwt-auth cd nodejs-jwt-auth# …...

nn.utils.clip_grad_value_

nn.utils.clip_grad_value_ 是 PyTorch 中的一个函数&#xff0c;用于在训练过程中对模型的梯度进行裁剪&#xff0c;以防止梯度爆炸&#xff08;gradient explosion&#xff09;问题。该函数对梯度的每个元素进行裁剪&#xff0c;将其限制在一个指定的最大绝对值范围内。裁剪后…...

Java后端面试模板(技术面)

1、自我介绍模板 面试官您好&#xff01;我是来自----大学计算机学院的一名大三学生&#xff0c;我的名字叫—。 在大学期间&#xff0c;我主要自学了一些主流的Java技术栈&#xff0c;其中主要包括&#xff1a;Java主流的框架&#xff1a;Spring MVC Spring Boot Spring Clou…...

【大语言模型】ACL2024论文-24 图像化歧义:Winograd Schema 挑战的视觉转变

【大语言模型】ACL2024论文-24 图像化歧义&#xff1a;Winograd Schema 挑战的视觉转变 目录 文章目录 【大语言模型】ACL2024论文-24 图像化歧义&#xff1a;Winograd Schema 挑战的视觉转变目录摘要研究背景问题与挑战如何解决核心创新点算法模型实验效果&#xff08;包含重要…...

Docker 安装和使用

#Docker 安装和使用 文章目录 1. 安装2. 干掉讨厌的 sudo3. 使用镜像源3.1. 使用 upstart 的系统3.2. 使用 systemd 的系统 4. 基本使用4.1. 容器操作4.2. 镜像操作 5. 网络模式说明5.1. bridge 模式5.2. host 模式5.3. container 模式5.4. none 模式 6. 查看 Docker run 启动参…...

nginx网站服务

nginx介绍&#xff1a; 1、高并发&#xff0c;轻量级的web服务软件 2、稳定性高&#xff0c;系统资源消耗率低 对http的高并发处理能力高&#xff0c;单台物理服务器可以支持30000-50000个并发。 一般来说在工作中&#xff0c;单台的并发一般在20000. nginx的功能介绍&…...

MATLAB 手写判断点在多边形内外的2种方法(87)

MATLAB 手写判断点在多边形内外-方法1(87) 一、算法介绍二、算法实现1.方法1(代码+测试)2.方法2(代码+测试)三、结果一、算法介绍 手动实现两种方法,判断点在多边形的内部还是外部, 具体实现和测试代码如下,使用前请自行验证。(代码复制粘贴即可使用) 二、算法实现…...

Android SurfaceFlinger layer层级

壁纸作为显示的最底层窗口它是怎么显示的 1. SurfaceFlinger layer层级 锁屏状态dump SurfaceFlinger &#xff0c;adb shell dumpsys SurfaceFlinger Display 0 (active) HWC layers: -----------------------------------------------------------------------------------…...

零基础快速掌握——【c语言基础】数组的操作,冒泡排序,选择排序

1.数组 内存空间连续&#xff1a; 2.定义格式 数组的定义格式&#xff1a; 数组分为一维数组、二维数组、以及多维数组&#xff0c;不同类型的数组定义格式时不一样 2.1 一维数组的定义 数据类型 数组名 [数组长度]&#xff1b; 解释&#xff1a; 数据类型&#xff1…...

个人IP建设:简易指南

许多个体创业者面临的一个关键挑战是如何为其企业创造稳定的需求。 作为个体创业者&#xff0c;您无法使用营销团队&#xff0c;因此许多人通过推荐和他们的网络来产生需求。因此&#xff0c;扩大您的网络是发展您的业务和产生持续需求的最佳策略。 这就是个人IP和品牌发挥作…...

【Unity高级】如何获取着色器(Shader)的关键词

在动态设置Shader时&#xff0c;会需要通过EnableKeyword, DisableKeyword来完成。但一个Shader有哪些关键词呢&#xff1f;Unity的文档中并没有列出来&#xff0c;但我们可以通过遍历Shader的KeywordSpace来查看。 1. 代码如下 using UnityEngine;public class KeywordExamp…...

OSS文件上传

1、我们这个系统对接的阿里云OSS需要先对接小鹏OSS系统获取accessKeyId、accessKeySecret&#xff0c;这个可以忽略 aliyun:oss:endpoint: https://oss-cn-hangzhou.aliyuncs.combucketName: xp-xpd-experiencedomain: https://xp-xpd-experience.oss-cn-hangzhou.aliyuncs.co…...

时序预测算法TimeXer代码解析

在时序预测领域&#xff0c;如何有效地利用外部变量&#xff08;exogenous variables&#xff09;来提升内部变量&#xff08;endogenous variables&#xff09;的预测性能一直是一个挑战。 在上一篇文章中&#xff0c;我结合论文为大家解读了TimeXer框架&#xff0c;今天&…...

【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug

created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区&#xff0c;Zotero 中文维护小组&#xff0c;Zotero 插件&#xff0c;Zotero 中文 CSL 样式 数…...

Hive 分桶表的创建与填充操作详解

Hive 分桶表的创建与填充操作详解 在 Hive 数据处理中&#xff0c;分桶表是一个极具实用价值的功能&#xff0c;它相较于非分桶表能够实现更高效的采样&#xff0c;并且后续还可能支持诸如 Map 端连接等节省时间的操作。不过&#xff0c;值得注意的是&#xff0c;在向表写入数…...

docker怎么commit tag push?

在 Docker 中&#xff0c;commit、tag 和 push 是用于创建和推送自定义镜像到仓库的三个不同步骤。以下是每个命令的详细说明和使用方法&#xff1a; ### 1. docker commit 当你对一个运行中的容器做了修改&#xff0c;并希望将这些修改保存为一个新的镜像时&#xff0c;可以使…...

全面替换VMware,南昌大学一卡通的硬核智慧

将一昼夜分为十二时辰 是古人的博大智慧 晨光熹微&#xff0c;门扉轻启&#xff0c;负笈而行 智慧校园的“十二时辰”启幕新章 一、数字南大&#xff1a;一卡通打卡校园十二时辰 时辰轮转&#xff0c;一时有一时的使命师生们是如何高效、便捷地度过每个时辰&#xff1f;一张充…...

SpringMVC ,ioc和aop

IOC和AOP IOC 控制反转&#xff0c;将应用程序的控制权交给spring容器管理&#xff0c;而不是应用程序本身 1.创建一个mapper&#xff0c;测试用&#xff0c; 就写个普通方法 public class UserMapper {public void addUser(){System.out.println("dao层新增");} …...

3GPP R18 LTM(L1/L2 Triggered Mobility)是什么鬼?(三) RACH-less LTM cell switch

这篇看下RACH-less LTM cell switch。 相比于RACH-based LTM,RACH-less LTM在进行LTM cell switch之前就要先知道target cell的TA信息,进而才能进行RACH-less过程,这里一般可以通过UE自行测量或者通过RA过程获取,而这里的RA一般是通过PDCCH order过程触发。根据38.300中的描…...

Ansys Maxwell:Qi 无线充电组件

Qi 无线充电采用感应充电技术&#xff0c;无需物理连接器或电缆&#xff0c;即可将电力从充电站传输到兼容设备。由 WPC 管理的 Qi 标准确保了不同无线充电产品之间的互操作性。以下是 Qi v1.3 标准的核心功能&#xff1a; Qi v1.3 标准的主要特点 身份验证&#xff1a;确保充…...

Neo4j 图数据库安装与操作指南(以mac为例)

目录 一、安装前提条件 1.1 Java环境 1.2 Homebrew&#xff08;可选&#xff09; 二、下载并安装Neo4j 2.1 从官方网站下载 2.1.1 访问Neo4j的官方网站 2.1.2 使用Homebrew安装 三、配置Neo4j 3.1 设置环境变量(可选) 3.2 打开配置文件(bash_profile) 3.2.1 打开终端…...

基于MFC绘制门电路

MFC绘制门电路 1. 设计内容、方法与难点 本课题设计的内容包括了基本门电路中与门和非门的绘制、选中以及它们之间的连接。具体采用的方法是在OnDraw函数里面进行绘制&#xff0c;并设计元器件基类&#xff0c;派生出与门和非门&#xff0c;并组合了一个引脚类&#xff0c;在…...

Gitee上获取renren-fast-vue install并run dev错误处理

目的&#xff1a;获取一个手脚架、越简约越好、越干净越好、于是看上了renren-fast-vue… 前端&#xff1a;vue2 后端&#xff1a;jdk1.8 mysql 5.7 SpringBoot单体架构 一开始只是下载前后端项目到本地&#xff0c;一堆乱七八糟的错误&#xff0c;网上找的资料也参差不齐… …...

sdk项目的git 标记新tag的版本号

在 Git 中&#xff0c;tag 是用来标记某个特定的提交点&#xff08;通常是发布版本或重要的里程碑&#xff09;的工具。通过 git tag&#xff0c;你可以为版本号创建标记&#xff0c;帮助团队跟踪不同版本的代码。 如果你想创建一个新的版本号标签&#xff0c;可以按照以下步骤…...

学习日志022 -- python事件机制

作业&#xff1a; 1】思维导图 2】完成闹钟 main.py import sysfrom PySide6.QtCore import QTimerEvent, QTime,Qt from PySide6.QtGui import QMovie,QMouseEvent from PySide6.QtWidgets import QApplication, QWidget from Form import Ui_Formclass MyWidget(Ui_Form,Q…...

JAVA八股文-运行篇-创建项目运行(1)

前置环境搭建:jdk、maven、idea、linux环境 一、创建一个java项目 File->New->Project 二、填写基本信息 三、完成&#xff0c;写了一段代码 四、打包 五、本地运行&#xff0c;运行和debug二选一 六、上传至linux环境 七、linux环境下命令执行 7.1 指定Main方法类 …...

Vue Web开发(二)

1. 项目搭建 1.1. 首页架子搭建 使用Element ui中的Container布局容器&#xff0c;选择倒数第二个样式&#xff0c;将代码复制到Home.vue。 1.1.1.下载less &#xff08;1&#xff09;下载less样式 npm i less   &#xff08;2&#xff09;下载less编辑解析器 npm i less…...

Midjourney Describe API 的对接和使用

Midjourney Describe API 的对接和使用 Midjourney Describe API 的主要功能是通过上传图片&#xff0c;获取对图片的描述。使用该 API&#xff0c;只需要传递图片文件地址&#xff0c;API 会返回图片的详细描述。无需繁琐的参数设置&#xff0c;即可获得高质量的图片描述。 …...