网络原理TCP/UDP详解

news2024/12/27 10:24:52

目录

传输属的几种格式

1.xml:通过成对的标签表示键值对信息。

2.json:当前更主流一点的,网络通信的数据格式

3.yml(yaml)强制要求数据的组织格式

4.google protobuffer

传输层

1.端口号:

UDP协议

关于校验和:

CRC校验和(循环冗余校验)

TCP协议

4位首部长度

保留(6位)

可靠传输核心功能之一/TCP核心机制一:

确认应答,感知到对方是否收到

TCP传输数据:

确认序号

再谈先发后至

丢包

TCP如何让应对丢包?

可靠传输核心功能之二/TCP核心机制二:超时重传

TCP核心机制三:连接管理之三次握手

为什么要进行三次握手?意义何在?

连接管理之二,四次挥手

TCP核心机制四:滑动窗口

滑动窗口出现丢包的情况

TCP核心机制五:流量控制

TCP核心机制六:拥塞控制

TCP核心机制七:延时应答

TCP核心机制八:捎带应答

TCP核心机制九:面向字节流


网络原理站在具体协议的角度进一步讨论,互联网中主流的是TCP/IP五层协议。

应用层是程序员日常开发最常用的一层,这一层的协议可以由我们自己实现也可以使用大佬创建好的。

其他层的协议,操作系统,硬件,驱动都是已经实现好的,程序员不能自定义。

传输属的几种格式

自定义协议并不是非常遥远的事情,很简单很朴素。主要分为两个步骤:

1.明确前后端交互过程中,需要传递哪些信息。

一个外卖界面要有商家列表,此处传递的信息就是用户的ID,用户所处的位置,用户的评分等等。

2.明确,组织这些信息的格式。(使用现有的格式)

当前的信息组织个是有很多,但是要确保前后端使用的是同一个格式。

使用文本行来组织上述数据:

请求:用户ID,用户位置,店铺评分\n;

响应:商家ID,商家位置,商家评分\n;

实际开发中很少使用文本行,有这么几种格式:

1.xml:通过成对的标签表示键值对信息。

<request>

        <userid>1001<userid>

        <position>E45N60<position>

<request>

每个标签都是成对存在的,这就非常消耗网络带宽。网络通信中,带宽是非贵的硬件设备。

xml也可以作为配置文件,xml与html相似,html也是通过成对的标签夹住一些内容的。

xml里的标签都是程序员自定义的。html的标签都是固定的(每个标签都有自己的含义)

2.json:当前更主流一点的,网络通信的数据格式

相比于xml,可读性更加好,同时也能够节省网络带宽

{

        "user":1001,

        "position": "E60S45"

}        

json也是“键值对”格式,

键和值:分割

键值对之间使用,分割

所有键值对用 { } 包含起来。

可读性很好,但是没有明确要求数据的格式,就会有些极端的情况。

比如:{ “userid":2001,"position" : "S60E45" },这样也是不好看的。

3.yml(yaml)强制要求数据的组织格式

yml要求键值必须独占一行,而且”嵌套结构“必须通过缩进表示,强制要求成为可读性非常高的格式。

request:

        userid:1001

        posiiton: "E45N60"

4.google protobuffer

前三个方案都是关注可读性,protobuffer关注性能,牺牲可读性(通过二进制来组织数据)

而protobuffer直接通过 ”位置“约定字段含义,不需要传输 key的名字,也会针对传输的数值进行二进制编码,起到一些压缩效果。

极大的缩减啦传输数据的体积,减少啦消耗的带宽,传输的效率更高。但是二进制数据无法肉眼阅读,调试程序时,就会比较麻烦。


传输层
1.端口号

是一个整数用来区分不同的进程。同一个时刻同一个机器上的同一个协议,一个端口只能被一个进程绑定。一个进程可以绑定多个端口号。

服务器绑定多个端口控制端口,调试端口,监控端口等等。

端口号两个字节表示,0->65535,其中0->1023已经是知名端口。日常开发会避开这些端口.虽然是知名端口但是其中大部分已经使用不上了,现在一些知名的服务器使用的端口号反而是1024以上的了。


UDP协议

学习网络协议主要就是学习 ”数据格式“,”报文格式“

 表格中端口号,长度这些属性换行了,但是实际中这些都是在同一行的元素。

前四个字段一共8字节,长度是固定的。报头的四个字段没有指定分隔符,而是通过固定的长度来进行区分的。

使用两个字节表示端口号范围是0->65535,如果端口号是10W,那么就会发生截断。

UDP报文长度就是指 报头+荷载长度。单位是字节。

比如报文长度是1024,那么整个UDP长度就是1024字节。

最大是65535字节,约为64KB.

网络通信中四个关键信息:源IP(发件人地址),目的IP(收件人信息),源端口(发件人电话),目的端口(收件人电话)。

因为UDP的长度是有限制的,传输数据的时候可不可以把UDP长度单位改为4个字节?

不可以,因为数据传输的两端UDP要保持统一,网络协议是不可以随便修改的,即使我们修改的自己电脑的UDP实现,但是我们改变不了所有客户端上的UDP实现。相比于修改UDP协议,不如使用新的协议替代UDP协议,这种方式更简单一些。

关于校验和:

前提:网络传输中,非常容易出现错误。因为大气中的光信号/电信号/电磁波可能会影响到传输信号的改变。(电场与磁场会相互影响的)。比特位会翻转:0->1,1->0

校验和存在的目的就是能够 ”发现“或者 ”纠正“这里出现的错误,就可以给传输的数据中引入额外的信息(checksum),用来发现/纠正 传输数据中的错误。 

这里只是发现错误,携带额外信息很少。如果是发现错误并且修改那么要携带的额外的信息就要很多。

如果发现错误就会丢弃掉,并不会让对方重发。

校验和具体是怎么工作的呢?

根据每一段的数据内容片段生成校验和, 

举例:

比如每个书名就是一段数据,校验和就根据这些数据的片段生成校验和, 比如取每个书名的第一个字作为校验和,如果第一个字对上了那就说明这个书名是对的

也有书名第一个字是对的,但是中间的字出错,恰好没有校验出来这种情况也是有的,但是好的校验算法发生这个问题的可能性很低.


CRC校验和(循环冗余校验)

UDP中使用两个字节作为校验和的长度, 把UDP数据报整个遍历一遍,分别取出每个字节 进行累加,由于数据可能会很大, 就会使结果溢出,但是没有关系,重点关心不是加的和最终是多少 ,而是关心校验和结果是否会在传输发生改变.

计算校验和的过程中是否能会出现两个不同的数据生成校验和相同呢? 

可能会,但是概率非常之低.  但是这个问题对于CRC来说相对高一点, 实现校验和除了使用CRC,还会使用另外两个典型的算法:MD5,和SHA1

MD5算法本质上是一个"字符串hash算法".  背后实现的是数学公式.

MD5 优点:定长,分散,不可逆;

1.定长:无论输入的字符串多长,算出的md5结果都是固定长度.------>适合做校验算法

2.分散:输入的内容,哪怕只有一点点改变,得到的md5值都会相差很大 ------>适合做hash算法

3.不可逆:根据输入的内容,计算MD5, 非常简单,但是想要已知md5值,得到初始内容理论不行--->做加密算法

得到的是十六进制的数,仅仅是相差一个字母得到的加密结果却相差甚远.越分散,越不容易发生hash冲突.


TCP协议

相比于UDP更加复杂

4位首部长度

TCP的报头长度,是四个比特位  0000-->1111,此处的单位长度是4字节,也就是最大报头长度是2^8*4字节. 这个4字节单位长度是当年大佬发明TCP约定俗成的.

保留(6位)

这个是保留位,现在虽然不用,但是未来TCP需要新增属性或者某个属性的长度不够用了,就可以把保留位拿出来应对.   充分吸收啦UDP的教训: 报文长度没法扩展,

TCP的基本特点:有链接,可靠传输,面向字节流,全双工

可靠传输是在代码层面感知不到的, 是系统内核完成啦这份工作. TCP的核心机制就是可靠传输.

可靠传输不能做到 100%的送达,只能尽可能使数据送达到对方.

1.能感知到对方是否收到,

2.发现对方没有收到就会进行重传

可靠传输核心功能之一/TCP核心机制一:
确认应答,感知到对方是否收到

所谓感知就是要靠对方告诉你是否收到.

举例:

这个时候小明在收到应答报文的情况下知道小红同意的情况下会进行下一步的准备.

但是如果小明发送多个消息就可能产生歧义

如果应答报文按照上述的顺序进行传输就没有问题.但是网络传输中的数据经常会发生先发后至的情况,因为传输两个数据报不一定都是走同一个路线,走不同的路线传输的到达的时间也不一样.

所以就有可能发生如下为情况

所以针对应答报文先发后至的情况通过添加 "编号" 可以区分出数据的先后顺序

这样即使收到的应答报文的顺序混乱 也可以区分出来针对那一条的数据报的应答报文

如何编号?

由于TCP是面向字节流的,实际上的编号不是按照 "第一条""第二条"这样的编号方式进行的.

而是按照"字节", 第一个字节,,,,,第100字节

每个字节都有独立的不同的编号, 编号之间是连续递增的.

按照字节编号这样的机制,就成为"TCP"序号, 应答报文中针对之前收到的数据进行对应的编码,称为 "TCP确认序号 "

32位序号:表示的就是TCP荷载中第一个字节的序号开始到32位结束,由于序号是连续递增的,所以也就是知道了每一个`序号.

TCP传输数据:

32位序号/4字节 最大表示0->42亿九千万, 意味着TCP一次传输的最多4GB内容. 

TCP是面向字节流的, 一个TCP数据报 和 下一个TCP 数据报 携带的数据是天然可拼装的. 如果要传输一个很大数据 传输中就会多个TCP 数据报来携带, 传输的过程中 这些TCP数据报彼此之间携带的载荷都是可以在 接受方 自动被拼接起来的. 

不像使用UDP存在传输上限, 使用UDP就要考虑一次send的数据是否超过64KB, 使用TCP可以一次write, 也可以多次write,超过4GB也没有关系.


确认序号

确认序号的设定方式与前面发短信的例子有些不同. 

确认序号也是按照字节来编排的.

这里确认序号是1001开始,确认序号是从接收方收到的最后一个字节的序号的下一位开始.表示的含义是<1000的序号数据都收到了.因为TCP序号是顺序增长的.

对于应答报文来说,确认序号就会按照收到数据最后一个字节号+1的方式来填写.另外六个标志位的ack会设为1, 对于普通报文序号是有效的,确认序号是无效的. 对于应答报文 序号和确认序号都是有效的.只不过这里的序号是采用另一种方式编写的.

应答报文默认不携带数据.


再谈先发后至

TCP针对接受方收到的数据会在"接收缓冲区"重新排序, 使read到的数据一定是和发送方的数据顺序是一致的.

B接收方这会在操作系统内核里留有一端内存空间,作为"接收缓冲区",收到的数据就会现在内存缓冲区里排队等待,直到开头的数据到了,应用程序才能真正读取到里面的数据.

接收方这边调用read的时候 如果没有数据就会阻塞等待,scanner读取本质是InputStream.read.    

就算10001-2000 这个数据到了,但是1-1000这个数据没有到 B就不会让read读取这个数据,直到1-1001这个数据到了,才会解除阻塞, 读取数据.这个就是确保write的顺序 和 read的顺序始终是一致的


丢包

网络传输不是一帆风顺,可能会丢包。

丢包的原因有如下:

1.数据传输的过程之中,发生了比特位反转,这个数据的接收方/中间的路由器啥的计算校验和发现对不上了。就会把这个数据报丢掉,不继续往后转发不交给应用层使用。

2.数据传输到某个节点发现(路由器/交换机)发现这个节点负载太高啦单位时间内这个节点并不能转发这么多,那么多出来的就会丢弃掉。

丢包与否完全是随机的,不可预测的。

TCP如何让应对丢包?

能做的就是感知到是否丢包,如果丢包就重新再发一次。那么如何感知到丢包呢?

需要通过应答报文来区分,收到应到报文就说明没有丢包,没有收到就说明丢包了。但是网络中的数据传输需要时间的,发送方会给出一个”时间限制“,如果暂时没有收到应答报文会等待一段时间,超过这个时间限制就会认为这个包丢了,此后在再到这个包已经无效了。

丢包有如上两种情况:一种是数据压根没有传输到接收方,还有一种是接收方收到了数据在返回ack的时候这个ack丢了并没有被发送方收到。此时超过时间限制之后就会认为这个数据丢了,就会超时重传,也就是会把这个包重新传输一遍。但是此时接收方会受到两份一样的数据。

去重:TCP接收方会有一个缓冲区,先放入缓冲区里,会根据序号在缓冲区里找,如果找到两份一样的数据,就会把新收到的数据丢弃,确保应用程序调用read出来的数据是唯一不重复的。接收方会再次返回一个针对同一个数据的ack。


可靠传输核心功能之二/TCP核心机制二:超时重传

这个时间不是固定的,而是动态变化的

发送方第一次重传的时间是t1,如果重传之后仍然没有ack,会继续重传。第二次重传的时间是t2

t2 > t1 。 每次重传超时间的间隔都会变大,重传的频次都会降低。

每经过一次重传,超时间的间隔都会变大,到达接收方的概率都会提升很多。如果很多次重传都都没有顺利到达,说明网络丢包率已经非常高了,不能再继续使用了。

重传不会无休止进行 当重传次数一定后 就会认为放弃这个连接已经挂了,会进行 “重复/复位连接”,发送一个特殊的 “复位报文” 。如果网络恢复了,复位报文就会重置连接,使通信可以继续进行。如果网络还是有严重的问题,复位报文也没有回应,此时TCP就会单方面放弃这个连接。

连接就是通信双方各自保存对方的信息,有一方保存的信息释放掉,这个连接就无了。

总结:确认应答 与 超时重传 共同构建了TCP的 “可靠传输机制”。TCP的可靠传输,不是通过“三次握手,四次挥手”保证的。


TCP核心机制三:连接管理之三次握手

建立连接:

三次握手四次挥手,这里的握手和挥手指的是网络通信的次数,网络中的握手 就是发送不携带业务数据的(没有载荷,只有报头的)数据报,但是能起到打招呼的效果。

上述的连接就建立完成了,本来是四次交互但是中间两次合并了,就成为了三次握手。合并很重要分两次发送与和并发送 效率是打折扣的。

这里的syn 与 synchronized 相似, synchronized 表示互斥,syn表示同步。这里意思是客户端希望服务器可以与他统一步调完成后续操作。建立连接断开连接都会有超时重传。

建立连接是一个双向操作,A给B说需要保存你的信息(syn),B也要给A说保存你的信息(syn)

为什么要进行三次握手?意义何在?

三个方面:

1.投石问路,初步验证通信链路是否畅通,这是进行可靠传输的“前提条件”。

2.确认通信双方的发送能力 与 接受能力 是否都正常。

3.让通信双方在通信之前,对通信过程中的一些关键参数进行协商。

(避免前朝的箭,斩本朝的官)

为什么要进行协商?避免历史遗留的数据干扰本次连接,因为在传输数据时避免不了有的数据会迷路,以至于到下一次两个主机连接但是是不同的应用程序,此时那个迷路的数据就传输到了接收方,但是这个数据对于本次的连接已经没用了,所以就要舍弃,每次建立新的连接TCP的其实序号就会差距很大,如果发现某个数据的数据号都与之前都收到数据差距很大,那么它很有可能是之前遗留的数据,应该舍弃。

TCP的可靠传输是通过“确认应答”“超时重传”体现的,三次握手只有一定的支持性,但不是关键因素。


连接管理之二,四次挥手

四次挥手的目的是把各自保留的对端信息删除掉

这里的断开连接不一定是客户端主动,服务器也可以主动。

通信双方各自给对方发送“FIN”,各自返回对方的“ACK”,三次握手中间两次可以合并在一起,因为中间两次的操作SYN,ACK都是在操作系统内核完成的,同一时机就可以合并。

对于四次挥手来说,中间的ACK是在操作系统内核完成的,但是FIN的触发是通过应用程序调用close/进程退出,来触发的。所以两个操作执行的时机不一样所以很难合并。


LISTEN:服务器进入的状态,服务器端口绑定好后,相当于进入listen状态了,此时服务器就已经完成初始化了,准备迎接客户端了。

ESTABLISHED:客户端和服务器都会进入的状态,TCP连接建立完成(保存了对方的信息),接下来就可以进行数据业务的通信了。

CLOSE_WAIT:被动断开连接的一方会进入这个状态,先收到FIN的一方,”等待执行close“

如果发现存在大量的CLOSE_WAIT状态的TCP连接,说明被断开连接的一方代码可能有bug,排查close是否写了/执行到了。

TMIE_WAIT:主动断开连接的一方会进入这个状态,此时的TIME_WAIT按照时间等待,到一定时间后,连接就释放了。

为什么不直接释放,而是要等待一段时间呢?因为防止最后ACK丢包,被断开的一方发送FIN后再给被断开的一方返回一个ACK就知道了刚刚那个FIN没有丢如果直接收到FIN后断开,则发送FIN的一方不知道FIN有么有发送过去,而且如果最后一个ACK没有成功到达,也可以再次发送一个ACK。TMIE_WAIT存在的最长时间是2ML(ML是网络传输中消耗的最大时间)。系统不一样M时常也不一样。


TCP核心机制四:滑动窗口

可靠传输 会降低传输的效率,为了能够尽可能弥补效率的损失引入了滑动窗口

即使引入滑动窗口但是效率依旧比不上UDP

没有滑动窗口传输如下

每次需要收到ACK后才发下一个数据。

有滑动窗口

改进:把一次发送一个变为 一次发送一批,把多次等待ACK的时间,合并成一份时间了,批量发送的数据越多,认为效率越高。数据的量就是“窗口大小”

一次发送四个数据,当收到了第一个ACK之后,只发送下一个字节流,收到了2001的ack,就说明1-1000,1001-2000的数据已经得到应答了,因为在接收缓冲区这个写数据必须按顺序读取,不然会发生阻塞。此时会再发送6001-7001,7001-8001的数据。


滑动窗口出现丢包的情况

丢包情况一:数据报已经过去,但是ACK丢了。

这种情况不用担心,批量发送数据,批量ACK。 丢了多个ACK只是其中的一部分不会全部丢失。

虽然1001丢了,但是5001返回了,意味着5001之前的数据都已经收到了。

情况二:数据包丢了。

此时1-1000,2001-3000数据都收了,但是1001-2000数据丢失了。此后无论A给B传输那个序号断的数据,B返回的ACK都是1001,B就是在向A索要1001-2000的数据。当主机收到多个1001ACK后,主机就知道了1001的数据丢了,主机就会重新发1001-2000的数据。

当1001-2000数据传输过来后,由于2001-7000都是发过的,A会立即发送7001以后的数据。

快速识别那个数据包并且针对性的重传,其他都不需要重传这个过程称为:“快速重传”

快速重传:是滑动窗口搭配的超时重传。

快速重传与超时重传并不冲突:通信双方发送的数据比较小就会 按照“确认应答”“超时重传”规则

如果单位时间发送数据很多,就会按照“滑动窗口”“快速重传”规则。


TCP核心机制五:流量控制

流量控制约束发送方的发送速度

滑动窗口的窗口大小对于数据的传输性能是直接相关的,但是窗口不能无限大。

发送方发送的速度确保接受处能处理的过来 以及 中间的数据链路层也能应付得来。

A到B的传输不是直接给B,而是先将数据传输到B的接收缓冲区中(内核中的内存空间,每个socket对象都有一个这样的空间),这个缓冲区类似于一个阻塞队列BlockingQueue,然后B再调用read相关方法读取数据。

也可以通过定量的方式来实现制约。看内存缓冲区的空间大小。

空闲空间越大就可以认为应用程序处理数据的速度比较快,就可以让发送方发送的速度也快一点,设置一个更大的窗口

如果空闲空间按比较小,就可以认为应用程序处理数据的速度比较慢,就可以让发送方发的慢一点。设置一个更小窗口。

TCP中接收方收到数据的时候,就会把接收缓冲区剩余空间的大小通过ACK数据报反馈给发送方

下一步发送方就可以依据这个数据报来设置发送的窗口大小。

这个标红的16位窗口大小就是接收缓冲区的剩余空间的大小,这个属性只有在ACK报文中(ACK为一)才有效。

此处的16位表示的范围是64kb,但是这不意味着发送方的窗口就只有64kb。因为选项中可以设置一个特殊的选项 “窗口扩展因子”,发送方窗口大小 = 窗口大小 << 窗口扩展因子。

流量控制不是TCP独有的,其他协议也有流量控制(比如数据链路层也有协议,也支持流量控制)


TCP核心机制六:拥塞控制

这个操作也是和刚才的流量控制有关的。

流量控制 是在接收方的视角来限制发送方的速度的。

拥塞控制 是在传输链路的视角来限制发送方的速度的。

假设B的处理速度非常之快,难道A就能无限制速度的发送数据吗,不行 因为中间的链路上的设备可能承受不住。

如果此时标红的节点负载已经很高了,A以很快的速度发送,这个节点就有可能丢包。

流量控制就可以精准的 使用 接收缓冲区剩余空间 来衡量。

但是 拥塞控制 需要考虑的就很多:

1.中间结点非常多

2.每次传输走的路线不一定一样。

3.中将哪个节点遇到瓶颈都不好说

4.中间节点传输的数据不只有A的 还有其他设备的数据。

最终采用一种动态的模式来寻找最合适的发送速度

1.先拿找一个较小的速度进行发送

2.数据非常畅通没有丢包,说明传输数据整体比较畅通,就可以加快传输数据速度。

3.增达到一定值后,发现开始丢包,网络可能存在拥堵,就减慢传输速度。

4.减到一定程度后,不丢包就继续加速。

5.加速后又丢包了就继续减速。

拥塞控制中,窗口的大小具体变化过程:

1.刚开始传输数据,拥塞窗口非常小,用一个很小的速度来发送数据

2.发现并不丢包,就以指数增长窗口大小

3.增长到一定程度,达到某个阈值 就会停止指数增长,变为线性增长

4.线性增长,也会持续使发送的速度越来越快,达到某个阈值就会出现丢包。

此时就会减小窗口大小:

经典过时的方案,回归到开始非常小的初始值再重蹈覆辙,指数增长,线性增长

现在的方案:回归到新的阈值上,开始线性增长。(以后都不会指数增长了)

流量控制 会限制发送窗口,拥塞控制也会限制发送窗口,最终的窗口大小取决于这两个机制的得到的窗口较小值。流量控制与拥塞控制都是对可靠传输的补充


TCP核心机制七:延时应答

延时应答提高效率,是ACK返回时携带的窗口大小更大

如果此时ACK返回,那么返回的窗口大小就是4KB,但是要ACK延时返回 原有5KB又被接收方消耗掉3KB,此时再让ACK返回,那么ACK携带的窗口大小就是(4+3)KB,那么下一次又可以传入7KB的数据了。

但是延时返回ACK也不一定就会返回的窗口更大,因为接收方此时可能没有接收数据,延时的时候可能也会有新数据发过来。


TCP核心机制八:捎带应答

捎带应答在延时应答的基础之上 提高效率,把返回的业务数据 和 ACK 合二为一了。

网络通信中大部分是一问一答的形式

正常情况下,ACK 和 响应是不同时机的无法合并,但是ACK 涉及到“ 延时应答”返回时间就回往后拖,就可以能赶上下一次发送的响应了,于是响应的的信息中ACK也带上了。

本身ACK 不需要荷载,报头中ACK这一位设置为1,设置窗口大小值,设置确认序号。

而响应数据主要是设置荷载和ACK不冲突 可以共存

延时应答,捎带应答都是TCP提升性能的机制。


TCP核心机制九:面向字节流

读写 100 个字节数据 可以有很多种方式,一次读100个,一次读50个,一次都10个等等。

无论怎么读 最终接收方收到的数据就是100个字节。但是所有字节都是紧挨在一起的,这就是粘包问题。

面向字节流的数据大多都会涉及到粘包问题,粘的是TCP携带的荷载

应用层数据包在TCP的接收缓冲区中,连成一片黏在一起,称为“粘包问题”

应用程序需要读取接收缓冲区中的数据,由于TCP面向字节流,读取可以很多种方式

一次读取一个a,a,a,b,b,b,c,,,,,

也可以 aaa,bbb,ccc,  还可以:aa,a,bb,b,cc,c,,,,,

但是实际上aaa,bbb,ccc才正确的读法。

可以采用以下几种数据格式:

方案一:指定分隔符

xml , yml , json 都可以采用这种方案

适用于文本类的数据,在之前模拟的回显客户端服务器TcpEchosever的时候,约定请求响应都是以\n结尾

发送请求响应的时候,专门使用println写数据。

读取请求响应的时候,专门使用scanner.next 按照\n进行解析

前提是:数据内容不能包括\n, 保险起见可以使用ASCII表中比较靠前的“控制字符”.。

方案二:指定数据长度

protobuf 采用这种方案

比如 约定,每个应用层数据包,开头的2/4字节,表示 数据包的长度。

接下来应用程序读取的时候就按照 这个长度读取数据包,一个长度代表一个数据包。

UDP传输数据报不涉及以上问题。send/receive 得到的就是一个完整的数据报。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2055886.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3 组件管理 12 种神仙写法,灵活使用才能提高效率

SFC 单文件组件 顾名思义&#xff0c;就是一个.vue文件只写一个组件 模板写法 如果这个组件想要在别的组件里使用&#xff0c;就需要在另一个.vue中引入和使用、复用 h函数写法 使用 defineComponent h 去进行组件编写 JSX/TSX写法 使用 defineComponent JSX/TSX 去进行…

【html+css 绚丽Loading】 - 000008 三才虚空灵瞳

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽Loading&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495…

应用方案 | 降压型DC-DC电源管理电路 D2576介绍

概述 D2576是一款高效降压型DC-DC转换器&#xff0c;固定52KHz开关频率&#xff0c;可以提供最高3A输出电流能力&#xff0c;具有低纹波&#xff0c;出色的线性调整率与负载调整率特点。 D2576内置固定频率振荡器与频率补偿电路&#xff0c;简化了电路设计。PWM控制环路可以调节…

Rivian暂停亚马逊送货车生产,特斯拉Roadster再引关注

Rivian遭遇供应链挑战&#xff0c;暂停亚马逊送货车生产 电动汽车制造商Rivian近期宣布&#xff0c;由于零部件短缺&#xff0c;已暂停为零售巨头亚马逊生产商业送货车。这一决定标志着Rivian在应对供应链挑战方面遭遇了最新挫折。作为Rivian的最大投资者&#xff0c;亚马逊持有…

画板444

p31 画H1和H2的封装 立创里面这次有尺寸了没单位好像 给的1.02 他设的1.1焊盘可以大点 排针穿过去的&#xff08;别的焊盘也这样&#xff1f;&#xff09; 引脚编号 直接改成2.54 他焊盘直间的 距离了 刚才改成通用的直径了&#x1f605;&#x1f605;&#x1f605; 这能测尺寸…

金九银十,软件测试面试八股文【含答案+文档】

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 测试技术面试题 1、什么是兼容性测试&#xff1f;兼容性测试侧重哪些方面&#xff1f; 参考答案&#xff1a; 兼容测试主要是检查软件在不同的硬件平台、软件…

google seo基础宝典,新手必学

Google SEO 是什么&#xff1f; Google SEO是指针对谷歌搜索引擎优化网站排名的一种营销方式&#xff0c;旨在提升外贸网站在谷歌的品牌和产品曝光度&#xff0c;从而吸引外贸订单。具体做法是根据谷歌的搜索引擎排名规则&#xff0c;对网站的内容、结构、链接等方面进行优化&a…

C++竞赛初阶L1-13-第五单元-循环嵌套(29~30课)536: T456455 画矩形

题目内容 根据输入的四个参数&#xff1a;a,b,c,f 参数&#xff0c;画出对应的矩形。 前两个参数 a,b 为整数&#xff0c;依次代表矩形的高和宽&#xff1b; 第三个参数 c 是一个字符&#xff0c;表示用来填充的矩形符号&#xff1b; 第四个参数 f 为整数&#xff0c;0 代表…

测试资料2222

一 解决穷举场景&#xff1a;使用等价类划分法 适用场景 正向用例&#xff1a;一条尽可能覆盖多条 逆向用例&#xff1a;每一条数据&#xff0c;都是一条单独用例 完整的用例应该是等价类和边界值一块写 二 能对限定边界规则设计测试点 2.1选取正好等于、刚好大于、刚好小于…

搜维尔科技:【产品推荐】Manus Quantum Mocap Metagloves VR手套数据手套机械手训练专用手套

全新量子追踪技术 Quantum Mocap Metagloves通过使用毫米级精确的指尖跟踪传感器来提供高保真手指跟踪。传感器没有漂移&#xff0c;可提供高度准确且可靠的手指捕获数据。 手指追踪的新黄金标准 Quantum Mocap Metagloves使用精确的量子跟踪技术捕捉手部每一个细节动作。让您…

Unity与UE,哪种游戏引擎适合你?

PlayStation vs Xbox&#xff0c;Mario vs Sonic&#xff0c;Unreal vs Unity&#xff1f;无论是游戏主机、角色还是游戏引擎&#xff0c;人们总是热衷于捍卫他们在游戏行业中的偏爱。 专注于游戏引擎&#xff0c;Unity和Unreal Engine&#xff08;简称UE4&#xff09;是目前市…

软件测试 - 自动化测试(概念)(Java)(自动化测试分类、web自动化测试、驱动、selenium自动化测试工具的安装)

一、自动化的概念 ⾃动洒⽔机&#xff0c;主要通上⽔就可以⾃动化洒⽔并且可以⾃动的旋转。 ⾃动洗⼿液&#xff0c;免去了⼿动挤压可以⾃动感应出洗⼿液 超市⾃动闸⻔&#xff0c;不需要⼿动的开⻔关⻔ ⽣活中的⾃动化案例有效的减少了⼈⼒的消耗&#xff0c;同时也提⾼了⽣…

淘宝API常见问题解答

本文总结了4个淘宝API常见问题并给出解答&#xff0c;如果有其他关于淘宝API的问题&#xff0c;可以向点三客服提问。 问题1&#xff1a;如何获取淘宝订单&#xff0c;需用哪几个淘宝API&#xff1f; 回答&#xff1a;一般是3个淘宝API接口配合使用&#xff1a;先用taobao.trad…

发展数控教育机床提高制造创新能力

随着科技的不断发展&#xff0c;智能化教学设备在教育领域中得到广泛的应用。在中小学课堂中&#xff0c;智能化教学设备的应用可以提高教学效率&#xff0c;激发学生的学习兴趣&#xff0c;促进学生的全面发展。 "教育科技”展示的魅力&#xff0c;让我们对未来的创新教学…

zabbix“专家坐诊”第252期问答

问题一 Q&#xff1a;大佬们请问一下&#xff0c;为何最近12小时的CPU利用率&#xff0c;显示的是昨天中午到昨天凌晨&#xff1f;而不是昨天晚上到现在的&#xff1f;谢谢 A&#xff1a;看看指标有没有获取到今天的数据 Q&#xff1a;佬牛逼&#xff0c;果然一下就指出问题&a…

移动云电脑手机端3.0全新升级,畅享个人便捷管理,筑牢安全管控防线

在当今数字化飞速发展的时代&#xff0c;企业对于高效、便捷且安全的办公模式需求日益迫切。移动云电脑手机端3.0全新升级&#xff0c;迎来科技领域的又一突破。其基于企业管理平台为企业客户提供管理能力&#xff0c;实现对用户、终端、资源的全方位集中管控&#xff0c;助力提…

晶体管电路设计学习(二)增强输出的电路

晶体管放大电路的基础是在上一节介绍的共发射极放大电路。然而,该电路有一些缺点,如输出阻抗高,容易受到作为负载所接的电路的影响。因此,在构成实际放大电路时,必须对输出进行强化,即降低输出阻抗。 由此而引入本章所要介绍的射极跟随器(EmitterFollower)。 所谓射极跟随器,简…

App测试面试题汇总(一)

一&#xff1a;请介绍一下&#xff0c;APP测试流程&#xff1f; APP测试流程与web测试流程类似&#xff0c;分为如下七个阶段&#xff1a; 1.根据需求说明书编写测试计划&#xff1b; 2.制定测试方案&#xff0c;主要是测试任务、测试人员和测试时间的分配&#xff1b; 3.测…

Android逆向题解-攻防世界-Ph0en1x-100

jeb反编译apk 主要代码是if 那个判断&#xff0c;getFlag取字符串用getSecret加密&#xff0c;和输入字符串encrypt加密后再getSecret加密&#xff0c;进行比较&#xff0c;两边同样都是getSecret加密&#xff0c;那比较可以简化成this.getFlag() this.encrypt(s) 。 也就是输…

深入探讨C语言中的高级内存管理技术

目录 深入探讨C语言中的高级内存管理技术 高级动态内存分配策略 1. 内存池&#xff08;Memory Pool&#xff09; 2. 对象池&#xff08;Object Pool&#xff09; 内存碎片化与其优化技术 1. 内存碎片化的成因 2. 优化内存碎片化的策略 内存泄漏检测与修复 1. 内存泄漏…