【计算机网络】TCP协议——2.连接管理(三次握手,四次挥手)
目录
前言
一. 建立连接——三次握手
1. 三次握手过程描述
2. TCP连接建立相关问题
二. 释放连接——四次挥手
1. 四次挥手过程描述
2. TCP连接释放相关问题
三. TCP状态转换
结束语
前言
TCP——传输控制协议(Transmission Control Protocol)。是一种面向连接的传输层通信协议
什么是连接
TCP连接是指通过TCP协议在网络中建立的一种可靠的通信链路。TCP连接在应用层之间提供可靠,高效的通信方式,广泛应用于互联网上的各种应用,如网页浏览,电子邮件,文件传输等。
建立连接在操作系统中是需要有对应的数据结构管理,维护的。所以连接的建立,维护都是有成本的
为什么要建立连接
- 更好的保证可靠性:建立连接的过程其实就是让通信双方验证各自的发送能力和接收能力是否正常,当前发送接收两端信道是否通畅。
- 协商一些重要参数,如:序号初始值,MSS,是否启用SACK,等等。
MSS和SACK可参看【计算机网络】TCP协议报头详解的选项部分
TCP建立连接,通信,断开连接的流程总图如下:
一. 建立连接——三次握手
1. 三次握手过程描述
【1. 服务器初始化状态】
服务器端进程先创建传输控制块(TCB),socket()创建套接字listenfd,bind()将套接字和端口号绑定,服务器进程准备接收客户端的连接请求。然后服务器进程调用listen()函数,使listenfd成为监听套接字,后续连接都从监听套接字获取。此时服务器端进程处于监听(listen)状态,紧接着调用accept()函数,在listenfd套接字中等待客户的连接到来
服务器端进程调用函数顺序:socket => bind => listen => accept。当执行到accept函数时,服务器进程会一直处于阻塞状态,直到有客户连接请求到达才返回
【2. 客户端发起连接请求,发送SYN同步报文段,第一次握手】
客户端进程也创建传输控制块(TCB),socket()创建套接字,然后向服务器端发送连接请求报文段,这时请求报文段的首部标志位SYN=1,同时选择一个初始序号seq=x,这个初始序号x是随机产生的整数ISN。TCP规定,SYN报文段(即SYN=1的TCP报文段)不能携带数据,但要消耗一个序号。此时,客户端进程进入SYN-SENT(同步报文已发送)状态
客户端进程函数调用顺序:socket => connect。当客户端调用connect函数时,操作系统会自动bind(),客户端进程就会向服务器进程发送连接请求的SYN同步报文段
SYN=1的报文段称为同步报文段
ISN(Initial Sequence Number)初始序列号
seq序号,即当前发送的报文首字节的编号
【3. 服务器同意建立连接,回复确认信息,第二次握手】
服务器端进程收到连接请求报文,若同意建立连接,从listenfd中获取客户端信息,并且由服务器端操作系统向客户端进程发送SYN报文段给出确认。在确认报文的首部中,SYN=1,ACK=1,确认号ack=x+1 。同时也为自己选择一个初始序号seq = y。这个确认报文也不能携带数据,但同样要消耗一个序号。这时,TCP服务器进入SYN-RCVD(同步报文已收到)状态
TCP协议规定,只要接收方接收到数据,必须给发送方发送确认报文——报文首部ACK标志位为1
ack确认号,期望对方发送的下一个报文首字节的编号
【4. 客户端确认连接,发送确认连接信息,第三次握手】
客户端进程收到服务器进程的确认报文后,还要向服务器进程的SYN报文给出确认。在确认报文首部,ACK=1,确认号ack=y+1,序号seq=x+1。TCP标准规定,ACK报文可以携带数据,但如果不携带数据,则不消耗序号。在这种情况,客户端进程的下一个数据报文序号仍为seq=x+1。客户端在发送确认报文后,认为连接成功建立,先进入ESTABLISHED(已建立连接)状态。
当服务器端进程收到客户端发送的确认报文后,认为连接成功建立,进入ESTABLISHED(已建立连接)状态
上面给出的TCP连接建立过程叫做“三次握手”。注意,上图服务器发送给客户端的报文,也可以拆分为两个报文,即先发送ACK=1(ack=x+1)的确认报文,再发送SYN=1(seq=y)的同步报文。客户端收到服务器端的同步报文段,发送确认报文,过程会变成“四次握手”,但效果一样
2. TCP连接建立相关问题
问题1:TCP建立连接可以只有2次握手吗?
回答:肯定不行。理由:在握手过程中,我们看到客户服务分别在最后一次握手建立连接。如果是两次握手,那么最后的报文由服务器发送,客户端接收
如此,服务器就会先于客户端建立连接。这是万万不可的。
- 如果确认报文丢失,那么服务器就会维护不成功的TCP连接
- 会很容易遭受SYN洪水攻击,即攻击者发送大量SYN请求,两次握手会使得服务器对每个送达的SYN都建立连接,如此会消耗大量资源,容易导致服务器崩溃
- 出现已失效的连接请求报文突然又传送到服务器端,维护失效的连接
“已失效的连接请求报文”是如何产生的呢?
假定一种异常情况:客户端A发送的第一个连接请求报文在某个网络结点滞留了,延误到客户端A认为该报文丢失失效,本次连接失败时,请求报文到达了服务器B。此时该请求报文已经失效,但B并不知道,所以给客户端A发送确认报文,如果只有两次握手,那么此时服务器B发出确认报文,建立连接,进入ESTABLISHED状态
由于A没有再发出建立连接的请求,因此不会处理B的确认报文,也不会向B发送数据。但B却认为连接成功建立,并一直等待A发送数据,浪费资源
所以握手次数绝不能是偶数次,因为这样会使得服务器先建立连接,将维护连接的成本嫁接给服务器
问题2:TCP连接建立为什么需要3次握手?
理由一:奇数次握手,客户端优先建立连接。
理由二:防止已失效的连接请求报文突然又传送到了服务器端,因而产生错误。
理由三:三次握手是客户服务器验证双方信道通畅,发送接收能力无误的最小成本
- 一二次握手,验证了客户端的发送和接收能力
- 二三次握手,验证了服务器端的发送和接收能力
问题3:在TCP连接建立过程中,如果服务器一直收不到客户端的ACK确认报文,会发生什么?
操作系统会给每个处于SYN-RCVD状态的服务器进程设定一个计时器,如果超过一定时间还没有收到客户端第三次握手的ACK确认报文,将会重新发送第二次握手的确认报文,直到重发达到一定次数才会放弃
问题4:初始序列号ISN为什么要随机初始化?
seq序号表示的是发送的TCP报文数据部分的起始字节位置,服务器/客户端可以通过序号正确读取数据。如果不是随机分配起始序列号,那么黑客就会很容易获取客户端与服务器之间TCP通信的初始序列号,然后通过伪造序列号让通信主机读取到携带病毒的TCP报文,发起网络攻击
问题5:SYN洪水攻击如何解决
SYN洪水攻击:攻击者在短时间内伪造大量不存在的IP地址,向服务器不断地发送连接请求的SYN同步报文。服务器需要为每个请求发送SYN-ACK确认报文,并等待客户端的确认,但因为是不存在IP地址,所以要像问题三中那样,不断发送SYN-ACK确认报文,直到重发到一定次数才会放弃,但这样同样消耗资源。
解决方法:
- 缩短SYN Timeout时间。由于SYN洪水攻击的效果取决于服务器上保持的半连接数,这个值=SYN攻击频率*SYN Timeout,所以通过缩短从接收到SYN报文到确认这个报文失效并丢弃的时间,可以成倍地降低服务器的载荷
- 设置SYN Cookie。给每一个连接请求的IP地址分配一个Cookie,如果短时间内连续收到某个IP地址的大量重复SYN报文,就认定收到了攻击,以后这个IP地址的报文将直接丢弃
- 使用防火墙。SYN 洪水很容易就能被防火墙拦截
二. 释放连接——四次挥手
TCP连接的释放可以用“四次挥手”的过程来描述。数据传输结束后,通信双方都可以释放连接。现在客户端和服务器都处于ESTABLISHED状态。释放连接的过程如下图所示:
1. 四次挥手过程描述
【1. 客户端主动断开连接,调用close(fd)发送释放连接的FIN报文,第一次挥手】
客户端进程调用close(fd)关闭套接字,操作系统发送释放连接的FIN结束报文,并停止发送数据,主动关闭TCP连接。在结束报文的首部,标志位FIN=1,序号字段seq=u,等于前面已发送的数据的最后一个字节的序号+1.此时客户端进入FIN_WAIT_1(终止等待)状态,等待服务器发送确认报文。
TCP规定,FIN报文即使不携带数据,也要消耗一个序号。与SYN报文一样
【2. 服务器收到客户端发送的结束报文,发出确认报文段,第二次挥手】
服务器收到客户端发送的释放连接的FIN结束报文,立即发送确认报文,确认号ack=u+1,序号seq=v,等于服务器前面已发送的数据的最后一个字节的序号+1。服务器进入CLOSE_WAIT(关闭等待)状态。TCP服务器进程此时通知上层应用程序,客户端不向服务器发送数据了,但服务器若有数据发送,客户端仍要接收,此时TCP连接处于半关闭(half-close)状态。
客户端收到服务器的确认报文后,进入FIN_WAIT2(终止等待2)状态,等待服务器发送的FIN结束报文
【3. 服务器调用close(connfd)关闭套接字,释放连接,发送FIN结束报文,第三次挥手】
当服务器没有要向客户端发送的数据时,其应用进程调用close(connfd)通知TCP释放连接,向客户端发送FIN结束报文。结束报文中,FIN=1,假定序号seq=w(半关闭状态,服务器可能还发送了一些数据),同时还必须重复上次已发送过的确认号ack=u+1。此时,服务器进程进入LAST_ACK(最后确认)状态,等待客户端确认。
【4. 客户端收到服务器的FIN结束报文,发送确认报文,第四次挥手】
客户端在收到服务器的FIN结束报文后,向服务器发送ACK确认报文。在报文首部中,ACK=1,确认序号ack=w+1,序号seq=u+1(第一次挥手的FIN报文消耗一个序号)。然后客户端进入TIME_WAIT(时间等待)状态
此时TCP连接还没有释放掉,必须经过时间等待计时器(TIME_WAIT timer)设置的时间2MSL后,A才进入CLOSED状态,时间MSL(Maximum Segment Lifetime,最长报文寿命)即一个TCP报文存活的最长时间。RFC793建议2分钟,现在可以根据情况使用更小的MSL值。因此客户端进入TIME_WAIT状态,要经过4分钟才进入CLOSED状态,才可以建立下一个连接,当客户端撤销相应的传输控制块TCB,才结束这次TCP连接
服务器只要收到客户端的确认报文,就进入CLOSED状态。同样,服务器在撤销相应的传输控制块TCB后,就结束此次TCP连接
可以发现,先发起释放连接请求的一方,后结束TCP连接
2. TCP连接释放相关问题
问题1:为什么建立连接是三次握手,关闭连接是四次挥手
首先,建立连接也可以是四次握手,中间的SYN和ACK可以分成两次报文。其次关闭连接,中间服务器给客户端发送的确认报文和FIN结束报文也可以合并,但可能服务器方还有数据需要传输,FIN结束报文在上层调用close()时发送,此时服务器已没有数据传输。
发送FIN报文,只是表示本端不再继续发送数据,但还可以接收数据。TCP通信时全双工的,收到FIN报文,只是关闭一个方向的连接,此时TCP处于半关闭状态
问题2:为什么客户端在TIME_WAIT需要等待2MSL才进入CLOSED状态
理由一:保证客户端发送的最后一个ACK报文能到达对端,保证可靠的终止TCP连接。因为如果出现网络拥塞,该报文可能丢失,因而会使LAST_ACK状态的服务器收不到确认报文,而超时重传FIN报文,而客户端能在2MSL时间内收到重传的FIN报文。接着客户端重传一次确认,重新启动2MSL计时器。最后双方正常进入CLOSED状态
理由二:防止已失效的连接请求报文出现在本次TCP连接。客户端在发送完最后一个ACK报文后,再经过2MSL后,就可以使本次TCP连接持续时间内所产生的所有报文都从网络上消散。这样可以使下一个新的TCP连接不会出现之前旧的请求报文
问题3:TIME_WAIT状态何时出现?TIME_WAIT会带来哪些问题?
TIME_WAIT状态是主动发起关闭连接的一方在收到对方发送的FIN结束报文,并本端发送ACK报文后的状态。
TIME_WAIT的引入是为了让TCP报文得以自然消散,同时为了让被动关闭的一方能够正常关闭连接
- 服务器主动关闭连接:短时间关闭大量客户端连接,会出现大量TIME_WAIT状态,此时TCB并没有释放,占据大量的tuple(源IP地址、目的IP地址、协议号、源端口、目的端口),严重消耗着服务器的资源。
- 客户端主动关闭连接:短时间内大量的短连接,会大量消耗客户端主机的端口号,毕竟端口号只有65535个,断开耗尽了,后续就无法启用新的TCP连接了。
问题4:解决TIME_WAIT状态引起的bind()函数执行失败
问题场景:因为主动关闭连接最终会进入TIME_WAIT状态,此时bind的IP地址,端口号都没有释放,重新启动服务会导致bind端口号失败。
解决方法:可以使用setsockopt()函数,设置socket描述符的SO_REUSEADDR选项,该选项可以让端口号被释放后立即再次使用,表示允许创建端口号相同但IP地址不同的多个socket描述符
问题5:半连接,半打开,半关闭的区别
半连接:在TCP连接建立的三次握手中,主动发起连接请求的一方不发最后一次的ACK确认报文,使得服务器阻塞在SYN_RCVD(同步收到)状态
半打开:如果TCP通信一方异常关闭(如断网,断电,进程被kill掉),而通信对端并不知情,此时TCP连接处于半打开状态,如果双方不进行数据通信,是无法发现问题的。解决方法是引入心跳机制,设置一个保活计时器(keepalive timer),以检测半打开状态,检测到就发送RST复位报文,重新建立连接
半关闭:主动发起连接关闭请求的一方A发送了FIN结束报文段,对端B回复了ACK确认报文段后,B并没有立即发送本端的FIN结束报文段给A。此时A端处于FIN_WAIT-2(结束等待2)状态,A仍然可以接收B发送过来的数据,但是A已经不能再向B发送数据了。这时的TCP连接为半关闭状态。
补充:
在Socket编程中,服务器Listen的第二个参数
三次握手是操作系统自助完成的,但服务器需要accept返回,才会拿到客户端的连接信息。如果服务器没有accept,这个连接就是全连接。backlog是全连接队列的容量-1。
Linux内核协议栈为TCP连接管理使用两个队列:
- 半连接队列(用来保存SY_SENT和SYN_RECV状态的请求)
- 全连接队列(accept队列,用来保存处于ESTABLISHED状态,但应用层没有调用accept取走的请求)
三. TCP状态转换
为了更清晰地看出TCP连接的各种状态之间的关系,下图给出了TCP的状态转换示意图。
说明:紫色框框是TCP状态,红色是服务器进程的正常状态转换,蓝色是客户端进程的正常状态转换,黑色是异常变迁,即出现问题时的状态转换。
服务端状态转化:
- 【CLOSE -> LISTEN】:服务器端调用listen后进入LISTEN状态,等待客户端连接
- 【LISTEN -> SYN_RCVD】:一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列,并向客户端发送SYN确认报文
- 【SYN_RCVD -> ESTABLISHED】:服务端一旦受到客户端的确认报文,进入ESTABLISHED状态,可以进行读写数据
- 【ESTABLISHED -> CLOSE_WAIT】:客户端主动关闭连接(调用close),服务器会受到结束报文,服务器返回确认报文并进入CLOSE_WAIT
- 【CLOSE_WAIT -> LAST_ACK】:进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器调用close关闭连接时,会向客户端发送FIN结束报文,进入LAST_ACK状态,等待客户端发送FIN结束报文的ACK确认报文
- 【LAST_ACK -> CLOSED】:服务器收到了对FIN结束报文的ACK确认报文,释放连接,撤销传输控制块TCB,释放相应的连接管理资源
客户端状态转化:
- 【CLOSED -> SYN_SENT】:客户端调用connect(),发送SYN同步报文段
- 【SYN_SENT -> ESTABLISHED】:connect()调用成功,进入ESTABLISHED状态,开始读写数据
- 【ESTABLISHED -> FIN_WAIT1】:客户端主动调用close(),向服务器发送FIN结束报文段,同时进入FIN_WAIT1状态
- 【FIN_WAIT1 -> FIN_WAIT2】:客户端收到服务器发送的对FIN结束报文的ACK确认报文,则进入FIN_WAIT2状态,开始等待服务器的FIN结束报文
- 【FIN_WAIT2 -> TIME_WAIT】:客户端收到服务器发送的FIN结束报文,进入TIME_WAIT状态,并发送最后一个ACK确认报文
- 【TIME_WAIT -> CLOSED】:客户端等待2MSL时间,才会进入CLOSED状态,释放连接资源
结束语
本篇博客到此结束,感谢看到此处。
欢迎大家纠错和补充
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
相关文章:

【计算机网络】TCP协议——2.连接管理(三次握手,四次挥手)
目录 前言 一. 建立连接——三次握手 1. 三次握手过程描述 2. TCP连接建立相关问题 二. 释放连接——四次挥手 1. 四次挥手过程描述 2. TCP连接释放相关问题 三. TCP状态转换 结束语 前言 TCP——传输控制协议(Transmission Control Protocol)。是一种面向连接的传…...

螺丝厂家:如何根据您的需求找到合适您的紧固件
螺丝是通用工具。它们几乎用于所有场景,并且它们的使用不限于任何一个行业。人们可以找到几乎所有周围都使用的螺钉和螺栓。在为工作选择合适的螺丝方面,人们应该记住一些事情。选择标准归结为紧固件的物理特性,包括制造它所用的原材料、施加…...
企业数字化转型进入深海区:生成式AI时代下如何制定数据战略
随着科技的不断进步,企业数字化转型已经不再是简单的概念,而是正在进入一个全新的深海区。在这个深海区,数据变得至关重要,而生成式人工智能(AI)的兴起更是推动了数字化转型的飞速发展。本文将探讨在这个生…...

html行内元素和块级元素的区别?
HTML中的元素可以分为两种类型:行内元素(inline)和块级元素(block) 文章目录 什么是行内元素什么是块级元素元素转换行内元素转块级元素块级元素转行内元素 区别总结 什么是行内元素 HTML的行内元素(inli…...

ResNet 原论文及原作者讲解
ResNet 论文摘要1. 引入2. 相关工作残差表示快捷连接 3. 深度残差学习3.1. 残差学习3.2. 快捷恒等映射3.3. 网络体系结构普通网络 plain network残差网络 residual network 3.4. 实施 4. 实验4.1. ImageNet分类普通的网络 plain network残差网络 residual network恒等vs.快捷连…...
liteflow规则引擎 执行Groovy脚本
在LiteFlow规则引擎中执行Groovy脚本的步骤相对简单。首先,确保你的项目中包含了LiteFlow的相关依赖。接下来,创建一个Groovy脚本规则,并使用LiteFlow引擎执行它。 以下是一个简单的示例: 添加LiteFlow依赖:在你的项…...

GZ015 机器人系统集成应用技术样题5-学生赛
2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书(学生赛) 样题5 选手须知: 本任务书共 24页,如出现任务书缺页、字迹不清等问题,请及时向裁判示意,并进行任务书的更换。参赛队…...

Spark编程实验二:RDD编程初级实践
目录 一、目的与要求 二、实验内容 三、实验步骤 1、pyspark交互式编程 2、编写独立应用程序实现数据去重 3、编写独立应用程序实现求平均值问题 4、三个综合实例 四、结果分析与实验体会 一、目的与要求 1、熟悉Spark的RDD基本操作及键值对操作; 2、熟悉使…...

CleanMyMac X这一款mac电脑清理垃圾文件软件好用吗?
CleanMyMac X您的 Mac。极速如新。点按一下,即可优化调整整个 Mac畅享智能扫描 — 这款超级简单的工具用于优化您的 Mac。只需点按一下,即可运行所有任务,让您的 Mac 保持干净、快速并得到最佳防护。CleanMyMac 是一款功能强大的 Mac 清理程序…...

四通道 DMOS 全桥驱动MS35631N/MS35631
MS35631N/MS35631 是一款四通道 DMOS 全桥驱动器,可以驱动两 个步进电机或者四个直流电机。每个全桥的驱动电流在 24V 电源下可以 达到 1.2A 。 MS35631N/MS35631 集成了固定关断时间的 PWM 电流校正 器,以及一个 2bit 的非线性 DAC &…...

JWT令牌的作用和生成
JWT令牌(JSON Web Token)是一种用于身份验证和授权的安全令牌。它由三部分组成:头部、载荷和签名。 JWT令牌的作用如下: 身份验证:JWT令牌可以验证用户身份。当用户登录后,服务器会生成一个JWT令牌并返回…...
elementui el-pagination分页组件查询的时候当前页不更新
elementui el-pagination分页组件查询的时候当前页不更新 <mypagination v-if"pageshow" :currentPage.sync"pageNum" :pagesize"pageSize" :pagetotal"pageTotal" pagefunc"pageFunc"></mypagination>1.在加的…...

C++——C++11(1)
时至今日,C标准已经到了C23,但是你要说哪一次提出的标准最经 典,那C11一定会被人提及,C11带来了数量可观的变化,其中包 含了约140个新特性,以及对C03标准中约600个缺陷的修正,这使得 C11更像是从…...
CoPilot究竟如何使用?
基本步骤说明 CoPilot是一款由GitHub开发的人工智能代码助手,可以提供实时代码建议和自动完成功能。下面是使用CoPilot的详细介绍: 安装:首先,你需要在你的代码编辑器中安装CoPilot插件。目前,CoPilot支持一些主流的代…...
前端(三)
1.表格标签 数据展示: jason 123 read egon 123 dbj tank 123 hecha ... <table> <thead><tr> 一个tr就表示一行<th>username</th> 加粗文本<td>username</td> 正常文本</tr></thead> 表头(字段信息)<tbody>…...
Maven知识
文章目录 一、概念1、官方文档2、什么是Maven? 二、相关知识1、Maven生命周期1.1、clean1.2、default1.3、site 2、Pom文件3、Pom常用元素3.1、项目基本元素3.2、<properties\></properties\>3.3、pom继承相关3.4、依赖管理相关3.5、构建管理相关3.6、&…...

美颜SDK是什么?视频美颜SDK在直播平台中的集成与接入教程详解
当下,主播们追求更加自然、精致的外观,而观众也期待在屏幕前欣赏到更为清晰、美丽的画面。为了满足这一需求,美颜SDK应运而生,成为直播平台的重要利器之一。 一、什么是美颜SDK? 通过美颜SDK,开发者可以…...

CSS基础面试题
介绍一下标准css盒子模型与低版本IE的盒子模型? 标准盒子模型:宽度内容的宽度(content) border padding margin 低版本IE盒子模型:宽度内容宽度(contentborderpadding) margin box-sizing 属性…...
L1-028 判断素数
本题的目标很简单,就是判断一个给定的正整数是否素数。 输入格式: 输入在第一行给出一个正整数N(≤ 10),随后N行,每行给出一个小于231的需要判断的正整数。 输出格式: 对每个需要判断的正整数&a…...

Scala多线程爬虫程序的数据可视化与分析实践
一、Scala简介 Scala是一种多种类型的编程语言,结合了针对对象编程和函数式编程的功能。它运行在Java虚拟机上,具有强大的运算能力和丰富的库支持。Scala常用于大数据处理、并发编程和Web应用程序开发。其灵活性和高效性编程成为编写多线程爬虫程序的理…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...