网络通信之传输层协议
文章目录
- 传输层在网络通信中扮演的角色
- 认识TCP协议
- TCP协议的多种机制
- 确认应答(ACK)机制
- 超时重传机制
- 连接管理机制🔺
- 滑动窗口
- 流量控制
- 拥塞控制
- 延迟应答
- 捎带应答
- 面向字节流
- 粘包问题
- TCP异常处理
- 总结
传输层在网络通信中扮演的角色

上图是网络通信中五个模块,今天所谈的传输层介于应用层和网络层之间,应用层是程序运行所在的地方,而网络层是定位主机从而发送信息的地方,因此传输层的基本任务就是完成信息在程序与发送之间的数据缓冲和异常处理。
有了这个大致的功能认知,这对于学习传输层的协议非常有帮助。
认识TCP协议
传输层协议其实包括UDP协议和TCP协议,这个在之前写的一篇应用层协议文章中提到过,应用层的代码实现是要基于传输层协议的。话说回来,由于UDP是面向数据报的一种协议,因此可靠性不如面向连接和字节流的TCP协议。因此TCP被广泛应用于各种网络领域的传输层,所以TCP是本篇博客的主角。
TCP协议作为一种协议,理所应当的具有其独特的数据规划,下面是抽象出来的数据分化图:

关于上图的具体数据的解释,部分内容后面着重讲解:
图中前5行(前20个字节)是TCP首部的标准长度,选项部分忽略,最后的数据部分就是应用层交付或需要接收的数据。也就是说前20个字节是报头,下面的数据就是报文(有效载荷)。
一、端口的意义:解决分用
协议需要解决的两个问题:
1.如何进行封装和解包?
TCP的数据格式已经写死了,就如上面的结构图一样,只需要按照顺序就可以拿取或者填充数据。
2.如何进行分用?
首行的端口号可以解决,其中目的端口表明了数据送往应用层的哪一个程序。
二、32位序号和32位确定序号的作用:应答部分讲解
三、4位首部长度的意义:
报头有标准长度(20字节),也就意味着报头是变长的,具体的大小由报头中的4位首部长度体现。4位bit取值范围为[0000-1111],单位是4字节,意味着报头的理论长度范围是[0-60]字节。但是由于最少是20字节,因此实际长度范围是[20-60]字节。
四、序号实现消息的应答机制
TCP作为一种可靠的传输手段,必须能够应对丢包的问题,解决这个问题的首要任务就是要能够检测出来数据丢失问题。32位序号是发送端每次发送数据的标识号,唯一表明一条数据。32位确认序号是接收端对于发送端消息的应答序号,该序号表明所有该序号之前的信息都被接收。具体细节单独讲解。
五、6位标志位
URG: 紧急指针是否有效
ACK: 确认号是否有效
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
RST: 对方要求重新建立连接; 把携带RST标识的称为复位报文段
SYN: 请求建立连接; 把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了, 称携带FIN标识的为结束报文段
六、16位窗口大小
表明缓冲区的大小,标识着一个接收端的接收能力。
七、16位检验和
发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题。 此处的检验和不光包含TCP首部, 也包含TCP数据部分。
八、16位紧急指针
标识哪部分数据是紧急数据。
TCP协议的多种机制
TCP协议作为一种可靠的传输协议,大佬们对其进行了多方面的考量和完善,出现了一系列的机制来保证安全、高效、尽量贴近现实需求。这些机制基本全是围绕TCP的报头内容设计的,因此接下来会对报头的部分数据进行详细解析。

确认应答(ACK)机制
一个消息有没有被对方接收到?在网络中如何确定这点?借助应答来解决。只要发送的消息有一条对应的应答被发送回来了,就认为消息成功被对方接收到了。这种机制就是确认应答机制,但是这种机制总会有一条最新的消息没有应答,这是不可避免的,只要保证部分百分百应答就可以。
确认应答机制主要是解决丢包的问题,毕竟数据在网络中传输不可能保证每次都是成功的,甚至即使传输成功也会由于种种原因而没有被客户端正确收到。这时就需要需要检测是哪些数据丢失,并对这些数据进行重传操作,直到数据传输成功。

其中[1-1000]、[1001-2000]、[2001-3000]这种数据的含义是[序号 - 数据大小+序号-1],数据大小的单位是字节,对于数据[1-1000],该数据序号是1,数据大小为(1000-1+1),则确认序号是1001,即确认序号=序号+数据大小。一旦出现丢包问题,确认序号将会保持不变,数值是最后一个确认收到的数据的确认序号:

事实上,序号还能保证数据能够一定的顺序被接收端处理。
超时重传机制
主机A作为发送端,主机B作为接收端,如果主机A给B发送了一条消息,在一定时间内收不到应答,就认为消息发送失败了。
可能的失败原因有三种:
1.主机A发送的消息丢包了。
2.主机B的应答丢包了。
3.网络拥塞,消息一直在路上而无法被接收。
无论哪一种情况,最终的结果都是主机A作为发送方重发数据,直到接收到主机B的应答。但是第二种情况由于是应答丢失,实际上主机B已经接收到了信息,因此主机A重发数据会导致数据重复,因此得依靠序号来实现去重,直接丢弃重复的数据。
那么这个超时怎么定义?多久算是超时呢?
最理想的情况下, 找到一个最小的时间, 保证 “确认应答一定能在这个时间内返回”。但是这个时间的长短, 随着网络环境的不同, 是有差异的。如果超时时间设的太长, 会影响整体的重传效率;如果超时时间设的太短, 有可能会频繁发送重复的包;TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间。
Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍。
如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传。
如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增。
累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接。

连接管理机制🔺
在正常情况下, TCP要经过三次握手建立连接, 四次挥手断开连接。这就是著名的三次握手和四次挥手原则。

客户端与服务端建立连接之后,连接的属性是由双方共同维护的,只要有一方进行了某种改变连接的操作,连接属性都会发生变化。
三次握手:
服务端:
• [CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接。
• [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文。
• [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行读写数据了。
客户端:
• [CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段。
• [SYN_SENT -> ESTABLISHED] connect调用成功, 则进入ESTABLISHED状态, 开始读写数据。
四次挥手:
服务端:
• [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进CLOSE_WAIT。
• [CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)。
• [LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接。
客户端:
• [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段, 同时进入FIN_WAIT_1。
• [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段。
• [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK。
• [TIME_WAIT -> CLOSED] 客户端要等待一个2倍的MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态。
为什么是TIME_WAIT的时间是2*MSL?
MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2*MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的)。同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN。 这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK)。
TIME_WAIT状态引起的服务端bind失败?
• 原因:
TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL的时间后才能回到CLOSED状态。使用Ctrl+C终止了server, 所以server是主动关闭连接的一方, 在TIME_WAIT期间仍然不能再次监听同样的server端口。MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s。
• 但是在某些情况下是不合理的:
服务器需要处理非常大量的客户端的连接(每个连接的生存时间可能很短, 但是每秒都有很大数量的客户端来请求)。这个时候如果由服务器端主动关闭连接(比如某些客户端不活跃, 就需要被服务器端主动清理掉), 就会产生大量TIME_WAIT连接。由于我们的请求量很大, 就可能导致TIME_WAIT的连接数很多, 每个连接都会占用一个通信五元组(源ip,源端口, 目的ip, 目的端口, 协议)。其中服务器的ip和端口和协议是固定的。如果新来的客户端连接的ip和端口号和TIME_WAIT占用的链接重复了, 就会出现问题。
• 解决办法:
使用setsockopt()设置socket描述符的 选项SO_REUSEADDR为1, 表示允许创建端口号相同但IP地址不同的多个socket描述符。
为什么要进行三次握手?而不进行两次握手甚至是一次握手?
• 一次握手:
客户端发送SYN给服务端,因为网络延迟的原因客户端没等到连接完成就走了。但服务端接收到了请求就认为连接建立成功了,一直等待客户端发送消息,白白浪费了服务端的资源。
• 二次握手:
客户端发送SYN给服务端,因为网络延迟的原因客户端没等到连接完成就走了。服务端接收到了迟来的SYN,并发送SYN+ACK给客户端,并认为连接建立成功。但是此时客户端早就走了,那么服务端的资源就又白白浪费了。
🔺以上两个情况在一般情况下影响也不是特别大,但是一旦有恶意的攻击者故意利用这点漏洞,快速地向一个服务端同时发送多次连接请求,就会导致服务端在短时间内资源被大量的无效连接资源占用,最终导致服务器崩溃。
首先三次握手会避免因为网络延迟问题而建立无效的连接,因为最后一次的ACK表明客户端一直在等着服务端的应答。三次握手虽然也没办法避免被攻击的情况发生,但是会大大加重攻击的代价,因为三次握手有客户端向服务端发送ACK,注定会导致客户端也会建立连接资源,导致攻击者与被攻击者都承担资源占用的后果。而一次握手和两次握手则不会产生这种效果,客户端往往只是发送请求而不真正建立连接资源,这是TCP协议的特性,不能看作是漏洞。
为什么要进行四次挥手?
这里我们得清楚一个概念:客户端关闭连接的最开始的潜台词是客户端不再发送任何信息了,即关闭接收缓冲区。但这并不意味着服务端就不给客户端发送信息,因此想要断开连接的客户端不能想走就走,不能直接关闭自己的发送和接收缓冲区,必须还得等到服务端完成所有的任务才会允许双方断开连接。
• 最开始的client->server的FIN意味着client不再发送信息。
• 接着server->client的ACK表示server已经知晓了client的状况,将server自己的接收缓冲区内的剩余信息全部取出来,之后就可以关闭server的接收缓冲区了。
• server->client的FIN表示server也不再给client发送信息了,意味着已经没有剩余的事情可以做了,可以断开连接了。双方都将自己的IO关闭。
• client->server的ACK表示client已经知晓最后的断开连接通牒了,完成断开动作。注意,最后的应答不属于IO操作,不属于信息的发送!
现实生活中形象点的例子:恋爱煲电话粥
男子张三和女子王丽谈恋爱,正值热恋,晚上打电话。([张三:client]、[王丽:server])
张三和王丽你侬我侬,说了半夜的情话,最后张三瞌睡了,实在是顶不住了。
张三:宝宝,我瞌睡了,咱不聊了,睡觉吧🥱
王丽:可以啊,但是刚刚的话我还没讲完欸,你先听我说完。(接着王丽将剩余的话讲完,张三一直听着,不敢直接挂断电话)
王丽:好啦,我讲完了,时间确实不早了,咱们睡觉吧,我也不讲哩。(王丽等着张三回应自己)
故事到这里就有了分叉点。
1.若是张三直接回应了王丽,则有如下情况:
张三:好嘞,睡觉咯😴
王丽听到后,知晓挂电话与分别的最终时刻到了,最终双方和和美美地挂断了电话。
2.此时若是张三很长时间没有回答王丽,则有如下情况,直到张三回应王丽:
王丽:你睡着了嘛?回我一声话啊,我好知道挂不挂电话去睡觉啊🙄
知识点补充:

listen函数作为服务端的监听函数,其中有第二个参数backlog在学习完连接管理机制之后可以做如下解释:
当服务端没有调用accept函数时,底层所能建立的最多的连接数是有限的(连接状态为ESTABLISHED),并且与backlog这个参数有关,具体最大数量为backlog+1,超过这个数目,建立的连接状态就不是完全连接了,连接状态是SYN_RCVD。
这样就会有一个类似队列一样的存在,去管理那些没来的及被accept的连接,一旦服务器空闲起来了,就会从队列中获取连接执行对应的任务。这大大减缓了服务器在满载的时候的处理压力,避免了重复建立连接的情况,提高了效率。但是队列的长度不宜过长,因为这个队列存在的意义就在于缓解压力,太长的队列维护起来本身就很浪费资源,因此均衡一点的长度是被期望的。
滑动窗口
确认应答策略, 对每一个发送的数据段, 都要给一个ACK确认应答.。收到ACK后再发送下一个数据段。这样做有一个比较大的缺点, 就是性能较差。尤其是数据往返的时间较长的时候。
如果一次性发送多条信息,使得他们的等待应答时间重合,那么信息发送的效率就会大大提升。但是发送多条信息的前提是接收端得有相应的接收能力,对应的就是接收端的接收缓冲区的大小,在TCP的报头中通过16位窗口大小体现。因此就在发送端的发送缓冲区中引入了滑动窗口的概念。

发送端发送缓冲区的抽象视角:

关于发送缓冲区的各部分数据含义:

• 滑动窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。
• 滑动窗口内的信息, 不需要等待任何ACK, 直接发送。
• 收到ACK后, 滑动窗口向后移动, 调整窗口位置,依旧认为窗口内的数据无需等待即可发送,接着发送尚未被发送的信息; 依次类推……
• 窗口越大, 则网络的吞吐率就越高。
• 在尚未收到ACK之前,滑动窗口是不会移动位置的,一旦需要重发某条信息并完成信息的重发后,窗口会立即进行调整。
流量控制
接收端处理数据的速度是有限的。如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送,就会造成丢包, 继而引起丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度。 这个机制就叫做流量控制 (Flow Control)。
• 窗口的大小是随着应答报头中的16位窗口大小改变而改变,接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端。16位表示的数据范围:[0-64]KB,但这并不意味着最多只能发送 64 KB大小的数据,在选项中可以对窗口大小进行扩充,但这一般不是编程猿所负责的了,所以不做深入解析了。

• 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度。
• 如果接收端缓冲区满了, 就会将窗口置为0。这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端。
可能存在的情况:

拥塞控制
拥塞控制是针对网络阻塞和网络异常这种情况所设计的,当网络比较拥堵时,如果上来就发送大量的信息时,就会恶化拥堵的情况。因此发送端最开始会先进入慢启动阶段,发送少量的数据,进行一种试探,再决定用多大的传输速度。
拥塞窗口在这种情况下被引入进来,最开始大小是1。
• 每收到一个ACK应答,阻塞窗口就会增大。
• 每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口。
• 拥塞窗口增长速度, 是指数级别的。“慢启动” 只是指初使时慢, 但是增长速度非常快。为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍。此处引入一个叫做慢启动的阈值,当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长。
• 当TCP开始启动的时候, 慢启动阈值等于窗口最大值,在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1。

少量的丢包, 仅仅是触发超时重传; 大量的丢包, 就认为是网络拥塞。
当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降。
拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案。
延迟应答
如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小。如果接收缓冲区接收了一部分数据,但是很快就被接收端给拿走了,空间很快就会被腾出来。这意味着接收者的处理能力较强,应答晚一点的话,应答中所携带的窗口大小就会更大。这意味着接收者向外界表示它的网络吞吐量较大,也就使得发送者一次能够发送更多信息,适当的延迟有助于挖掘接收者的处理潜能。
那么所有的包都可以延迟应答么? 也不是的。
数量限制: 每隔N个包就应答一次。
时间限制: 超过最大延迟时间就应答一次。
具体的数量和超时时间, 依操作系统不同也有差异。

捎带应答
在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的。也就是说,一条信息,不仅仅只有单纯的应答或是信息任务,而是二者兼备。

面向字节流
TCP协议下,使用socket函数创建网络套接字,实际上就是创建一个文件描述符,具有全双工性质。
全双工就是可以对同一个文件描述符同时进行读和写的操作,而不发生读写冲突,这就意味着读写双方的信息肯定不在一块空间里,而是单独的两块空间:接收缓冲区和发送缓冲区。

调用write时,数据会先写入发送缓冲区中。如果发送的字节数太长, 会被拆分成多个TCP的数据包发出。如果发送的字节数太短, 就会先在缓冲区里等待,等到缓冲区长度差不多了,或者其他合适的时机发送出去。
接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区。然后应用程序可以调用read从接收缓冲区拿数据。
另一方面, TCP的一个连接,既有发送缓冲区,也有接收缓冲区,那么对于这一个连接,既可以读数据,也可以写数据。
由于缓冲区的存在,TCP程序的读和写不需要一一匹配,即可以一次性读取或写入完所有的信息,也可以分批次多次读取或写入信息。
粘包问题
站在传输层的角度,TCP是一个一个报文过来的。 按照序号排好序放在缓冲区中。站在应用层的角度,看到的只是一串连续的字节数据。那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。上述问题就是粘包问题了,很类似于一屉包子挨得近了就容易粘在一起,分界线就模糊了。
解决的思路当然就是明确两个包之间的分界线。
对于定长的包,保证每次都按固定大小读取即可。
对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置。对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔符不和正文冲突即可)。但是这些都是TCP所要面临的问题,对于UDP来说, UDP是一个一个把数据交付给应用层。就有很明确的数据边界。站在应用层的站在应用层的角度,使用UDP的时候,要么收到完整的UDP报文,要么不收。不会出现"半个"的情况。
TCP异常处理
• 进程关闭
进程关闭的最后会自动关闭文件描述符,也就是会发送FIN信号,那么四次挥手就会正常完成。
• 机器重启
和进程终止的情况相同
• 异常断电
接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset。即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在。如果对方不在,也会把连接释放。
总结
TCP设计得这么麻烦,就是为了保证通信的可靠性,并且尽量提高通信的效率。
可靠性:校验和、序列号(按序到达)、确认应答、超时重发、连接管理、流量控制、拥塞控制
提高效率:滑动窗口、快速重传、延迟应答、捎带应答
那么如果用UDP实现类似于TCP的可靠传输,要根据具体的情景要求,加入对应的机制。
相关文章:
网络通信之传输层协议
文章目录 传输层在网络通信中扮演的角色认识TCP协议TCP协议的多种机制确认应答(ACK)机制超时重传机制连接管理机制🔺滑动窗口流量控制拥塞控制延迟应答捎带应答面向字节流粘包问题TCP异常处理 总结 传输层在网络通信中扮演的角色 上图是网络通信中五个模块ÿ…...
短视频app开发:如何提高视频播放稳定性
简介 如今,短视频已经成为人们日常生活中不可或缺的一部分,而短视频app的开发也日益成为了人们热议的话题。在短视频app开发的过程中,如何提高视频播放稳定性是一个非常重要的问题。本文将从短视频源码角度出发,分享提高短视频ap…...
软件测试,想找一份20k以上的工作需要掌握哪些知识?
都知道IT行业是高薪人员的聚集地,但想要成为高薪程序员却并不容易。月薪20k是测试工程师的一个门槛,想要突破就必须掌握更多的技能。 因为程序员职业发展很快,即使是相同起点的人,经过几年的工作或学习,会迅速拉开极…...
PostgreSQL标准复制方案
集群拓扑 假设我们使用4单元的标准配置:主库,同步从库,延迟备库,远程备库,分别用字母M,S,O,R标识。 M:Master, Main, Primary, Leader, 主库,权威数据源。S: Slave, Secondary, Standby, Sync…...
AOD实践,modis数据下载,modis数据处理
modis数据下载-数据读取-重投影-拼接-均值 一、数据下载 1、Cygwin安装 Cygwin安装教程:https://blog.csdn.net/u010356768/article/details/90756742 1.2 数据采集 现提供遥感数据下载服务,主要是NASA数据,数据下载网站包括:…...
常见的注册中心Nacos、Eureka
常见的注册中心 1.Eureka(原生,2.0遇到瓶颈,停止维护) 2.Zookeeper(支持,专业的独立产品。例如:dubbo) 3.Consul(原生,GO语言开发) 4.Nacos …...
逆向思维书籍推荐
《逆向思维》作者:德鲁克 《逆向思维法》作者:艾伦哈勃 《逆向思维:如何解决问题》作者:托尼布赖恩特 《逆向思维的力量》作者:李开复 《逆向思维:掌握创新的关键》作者:李嘉诚 《逆向思维》作…...
centos系统简析
服务器所使用的最多的系统之一便是Linux系统,Linux下centos系统也是常用的系统,今天来给大家详细说名下centos系统。 CentOS于2004年5月发布,作为一个完全免费且基于Linux内核的操作系统。CentOS 起源于 RHEL。其目标是提供一个免费提供的企…...
「SQL面试题库」 No_43 只出现一次的最大数字
🍅 1、专栏介绍 「SQL面试题库」是由 不是西红柿 发起,全员免费参与的SQL学习活动。我每天发布1道SQL面试真题,从简单到困难,涵盖所有SQL知识点,我敢保证只要做完这100道题,不仅能轻松搞定面试࿰…...
TEB算法详解 参数详解
teb算法的基本思路之前已经看完了,今天主要看一下teb算法的参数配置文件,分析一下每个配置参数的作用: teb的参数主要可以包含以下几个部分: 1、Trajectory Trajectory的参数顾名思义,就是对路径生效的一些参数&…...
JavaSE学习进阶day05_03 泛型(进阶)
第五章 泛型,之前基础班学习过泛型,但是学的不深入 需要我们掌握的内容:(掌握) 1,如何使用一个带有泛型的类 2,如何使用一个带有泛型的方法 代码示例: ArrayList<String> lis…...
Flutter 布局探索 | 如何分析尺寸和约束
theme: cyanosis 前言 本文来分享一下,通过查看源码和布局信息解决的一个实际中的布局小问题,也希望通过本文的分享,当你遇到布局问题时,可以靠自己的脑子和双手解决问题。 如下所示,将 TextField 作为 AppBar 组件的 …...
01-Java基础知识面试题(2020最新版)
Java概述 何为编程 编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并 终得到结果的过程。 为了使计算机能够理解人的意图,人类就必须要将需解决的问题的思路、方法、 和手段通过计算机能够理解的形式告诉计算机,使得…...
同一台电脑管理多个ssh key
默认情况下,我们在本地电脑生成的密钥都是 id_rsa 和 id_rsa.pub ,git 默认情况下也只会读取这个私钥,所以我们需要修改一些配置来支持多个SSH Key。 本文基于Linux系统,Windows系统类似 第一步:生成ssh公私钥 ljhp…...
《UVM实战》学习笔记——第七章 UVM中的寄存器模型2——期望值/镜像值、自动/显示预测、操作方式
文章目录 前言一、寄存器模型对DUT的模拟1.1 期望值和镜像值1.2 常见操作对期望值和镜像值的影响 二、prediction分类2.1 自动预测2.2 显式预测 三、访问寄存器方式四、mem和reg的联系和差别五、内建built_in sequence5.1 寄存器模型内建序列5.2 存储器模型内建序列5.3 禁止域名…...
OFDM-LS信道估计 MMSE信道估计公式推导
假设ofdmN个子载波之间是完全正交的,即不考虑ICI影响,通过发送训练序列来实现信道估计。 其中,在推导6.8的时候,需要将6.6先拆解一下。 X − 1 Y X − 1 ( X H Z ) X − 1 X H X − 1 Z H X − 1 Z X^{-1}Y X^{-1}(XHZ)…...
业界内分布式锁
技术主题 在分布式系统中,面对分布式微服务日益流行的场景,分布式锁一直是分布式系统老生常谈的内容。分布式锁可以防止用户重复点击,对于电商场景中,分布式锁可以防止用户重复下单,给用户带来更好的体验。 技术实现…...
基于Java+Springboot+Vue+elememt甜品屋蛋糕商城系统设计和实现
基于JavaSpringbootVueelememt甜品屋蛋糕商城系统设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系…...
C/C++每日一练(20230424)
目录 1. 只出现一次的数字 🌟 2. 有效的括号 🌟🌟 3. 递归反序正整数 🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 只出现一次…...
三百左右的蓝牙耳机哪个音质好?三百左右音质最好的蓝牙耳机推荐
在外出携带的数码产品中,蓝牙耳机的出现频率居高不下,一部手机,一副耳机已经成为不少人外出的标配。蓝牙耳机无外乎是用来听的,下面,我来给大家推荐几款三百左右音质好的蓝牙耳机,一起来看看吧。 一、南卡…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
