tcp特点+TCP的状态转换图+time_wait详解

tcp特点+TCP的状态转换图+time wait详解

目录

一、tcp特点解释

1.1 面向连接

1.1.1 连接建立——三次握手

1.1.2 连接释放——四次挥手

1.2 可靠的

1.2.1 应答确认

1.2.2 超时重传

1.2.3 乱序重排

1.2.4 去重

1.2.5 滑动窗口进行流量控制

1.3 流失服务(字节流传输)

1.3.1 tcp粘包概念

1.3.2 产生 TCP 粘包的原因

发送端原因

接收端原因

1.3.3 解决 TCP 粘包的方法

定长协议

分隔符协议

消息头 + 消息体协议

二、服务器接收多个客户端 

三、TCP(传输控制协议)的状态转换图

2.1 状态

2.2 转换


一、tcp特点解释

1.1 面向连接

1.1.1 连接建立——三次握手

在进行数据传输之前,TCP 需要通过 “三次握手” 来建立连接。具体过程为:客户端向服务器发送一个 SYN 包,请求建立连接;服务器收到 SYN 包后,向客户端发送一个 SYN + ACK 包,表示同意建立连接;客户端收到 SYN + ACK 包后,再向服务器发送一个 ACK 包,连接建立完成。这种方式确保了双方都有发送和接收数据的能力,并且双方对连接的初始序列号达成一致。

1.1.2 连接释放——四次挥手

数据传输结束后,TCP 使用 “四次挥手” 来释放连接。客户端发送一个 FIN 包,表示请求关闭连接;服务器收到 FIN 包后,发送一个 ACK 包表示同意关闭;接着服务器发送一个 FIN 包,表示自己也请求关闭连接;客户端收到 FIN 包后,发送一个 ACK 包表示同意关闭,连接释放完成。这种机制保证了双方都能正确地结束数据传输。

1.2 可靠的

1.2.1 应答确认

TCP 使用确认机制来确保数据的可靠传输。发送方发送数据后,会等待接收方的确认信息(ACK)。如果在一定时间内没有收到确认信息,发送方会重新发送该数据。例如,发送方发送了一个数据包,接收方收到后会返回一个带有确认号的 ACK 包,告知发送方已经正确接收了哪些数据。

1.2.2 超时重传

当发送方发送的数据丢失或者接收方返回的确认信息丢失时,发送方会在超时后重传数据。TCP 通过设置定时器来实现超时重传,定时器的时间会根据网络状况动态调整。

1.2.3 乱序重排

我们每发一个tcp报文都有相应的序号。TCP 保证字节流中的数据按照发送的顺序到达接收方。如果数据在传输过程中出现乱序,TCP 会在接收方进行重新排序,确保应用层接收到的数据是有序的

1.2.4 去重

俩个相同序号的报文去重

1.2.5 滑动窗口进行流量控制

滑动窗口用于控制数据的发送速率和流量,同时保证数据的可靠传输。发送方和接收方都有一个滑动窗口,窗口的大小表示可以发送或接收的数据量。滑动窗口越大代表我能发送的数据越大.发送方在发送数据时,会根据接收方的窗口大小来决定发送多少数据,避免接收方缓冲区溢出。窗口内的允许发送,窗口外的不允许发送

(不会丢包因为是可靠的,底层可能会丢但是会重传时间特别快,我们应用层感受不到)

1.3 流失服务(字节流传输)

多线程并发——给一个服务器同时链接俩个以上客户端

发送缓冲区:send数据写到这里

接收缓冲区:recv接收数据

TCP 将应用层的数据看作是无边界的字节流进行传输。发送方可以将多个应用层的消息合并成一个字节流发送,接收方需要自己从字节流中提取出各个消息。例如,应用层发送了两条消息 “Hello” 和 “World”,TCP 可能会将它们合并成一个字节流 “HelloWorld” 进行发送,接收方需要根据具体的协议来区分这两条消息。

这张图展示了 TCP 字节流服务的特性,主要体现以下几点:

发送端 - **应用层**:应用层通过多次调用 `send()` 函数分别发送 “hello”、“abc”、“test” 这些数据。`send()` 函数用于将应用层数据传递给传输层。 - **传输层**:TCP 协议将这些数据暂存于 TCP 发送缓冲区。TCP 为了提高传输效率,会根据自身机制(如窗口大小、拥塞控制等 )对发送缓冲区中的数据进行组合和封装。如图中所示,可能会把 “hello” 和 “abc” 组合在一起封装成一个 TCP 报文段,“test” 单独封装成一个 TCP 报文段。这种组合并非严格按应用层发送顺序和边界,而是根据 TCP 自身策略。

接收端 - **传输层**:接收端的 TCP 协议从网络中接收 TCP 报文段,先存储在 TCP 接收缓冲区。 - **应用层**:应用层通过 `recv()` 函数从 TCP 接收缓冲区读取数据。由于 TCP 发送时可能对数据进行了组合封装,接收端应用层调用 `recv()` 读取数据时,不一定能按发送端应用层的原始边界和顺序获取数据,可能会一次性读取多个发送端组合封装的数据,也可能分多次读取。 总体而言,该图展示了 TCP 字节流服务中,数据在发送端和接收端的处理过程,突出 TCP 并不保证应用层数据的边界,而是以字节流形式进行传输和处理。  

1.3.1 tcp粘包概念

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。而 TCP 粘包是在使用 TCP 进行数据传输时可能遇到的一个常见问题。

TCP 粘包指的是在 TCP 连接中,发送方发送的若干个数据包,到接收方接收时,这些数据包粘连在一起,接收方难以区分哪些字节属于哪个原始数据包的现象。 

1.3.2 产生 TCP 粘包的原因

发送端原因
  • Nagle 算法:TCP 为了提高传输效率,采用了 Nagle 算法。该算法会将小的数据包合并成大的数据包进行发送,以此减少网络中的数据包数量。例如,当你连续发送多个小数据包时,Nagle 算法可能会将它们合并成一个大的数据包发送,从而造成粘包。
  • TCP 缓冲区:TCP 协议的发送缓冲区用于暂存待发送的数据。如果发送方的数据产生速度大于网络的发送速度,那么数据就会在缓冲区中累积,当缓冲区满或者达到一定条件时,就会将缓冲区中的数据一起发送出去,这也可能导致多个数据包粘连在一起。
接收端原因
  • TCP 接收缓冲区:接收端在接收数据时,会将数据先存放在接收缓冲区中。如果接收方没有及时从缓冲区中读取数据,后续的数据也会不断地存入缓冲区,这样就可能导致多个数据包的数据混合在一起,形成粘包。

1.3.3 解决 TCP 粘包的方法

定长协议

规定每个数据包的长度是固定的。接收方按照固定长度来读取数据,这样就可以明确区分每个数据包。

分隔符协议

在每个数据包的末尾添加一个特殊的分隔符,接收方根据分隔符来区分不同的数据包。

消息头 + 消息体协议

在每个数据包的前面添加一个消息头,消息头中包含消息体的长度信息。接收方先读取消息头,根据消息头中的长度信息来读取相应长度的消息体。

二、服务器接收多个客户端 用fork做并发

它是一个简单的TCP服务器程序,它在本地6000端口上监听连接请求,接受客户端的连接,并为每个连接创建一个新的进程来处理

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);//创建监听套接字if( -1 == sockfd ){exit(1);}//定义套接字地址结构, ipv4,ipv5,unixstruct sockaddr_in saddr,caddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");//将套接字绑定到指定的IP地址和端口。如果绑定失败(返回-1),则打印错误信息并退出程序。int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//指定ip portif( -1 == res){printf("bind err\n");exit(1);}//使套接字进入监听状态,监听队列大小设置为5。如果监听失败(返回-1),则退出程序。res = listen(sockfd,5);//设置监听队列 大小是5if( -1 == res){exit(1);}//进入一个无限循环,等待客户端的连接请求。accept函数用于接受连接请求,并将客户端的地址信息存储在caddr中。while( 1 ){int len = sizeof(caddr);int c = accept(sockfd,(struct sockaddr*)&caddr,&len);//检查是否成功接受连接。如果失败,则继续下一次循环。if( c < 0 ){continue;}//创建一个新的进程来处理这个连接。如果创建进程失败,则关闭连接并继续下一次循环pid_t pid = fork();if( pid == -1 ){close(c);continue;}//在子进程中,进入一个无限循环,接收客户端发送的数据,并发送"ok"作为响应。如果接收失败或客户端关闭连接,则打印信息,关闭连接,并退出子进程。if( pid == 0 ){while( 1 ){char buff[128] = {0};int n = recv(c,buff,127,0);if( n<= 0 ){break;}printf("recv:%s\n",buff);send(c,"ok",2,0);}printf("client close\n");close(c);exit(0);}close(c);}
}

这个程序实现了一个简单的TCP服务器,它可以在本地6000端口上监听连接请求,接受客户端的连接,并为每个连接创建一个新的进程来处理。服务器接收客户端发送的数据,并发送"ok"作为响应。服务器使用多进程模型来处理多个客户端的连接。 

TCP客户端程序cli,它连接到本地服务器(127.0.0.1),发送消息,并接收服务器的响应

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>int main()
{//创建一个TCP套接字。AF_INET 表示使用IPv4地址,SOCK_STREAM 表示使用面向连接的流式套接字。int sockfd = socket(AF_INET,SOCK_STREAM,0);//检查套接字是否创建成功。如果失败(返回-1),则退出程序。if( sockfd == -1 ){exit(1);}//定义并初始化服务器的地址结构。memset 用于清零结构体,sin_family 设置为IPv4,sin_port 设置为6000端口(使用htons函数转换为网络字节序),sin_addr.s_addr 设置为本地地址127.0.0.1(使用inet_addr函数转换为网络字节序)。struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");//尝试连接到服务器。如果连接失败(返回-1),则打印错误信息并退出程序。int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if ( res == -1 ){printf("connect err\n");exit(1);}//进入一个无限循环,提示用户输入,然后使用fgets函数从标准输入读取一行文本(最多127个字符),存储在缓冲区buff中。while( 1 ){printf("input\n");char buff[128] = {0};fgets(buff,128,stdin);//检查用户输入是否为"end"。如果是,则退出循环。if( strncmp(buff,"end",3) == 0 ){break;}//发送用户输入的消息到服务器(不包括换行符),清空缓冲区,接收服务器的响应,并打印出来。send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("read:%s\n",buff);}close(sockfd);exit(0);
}

 这个程序实现了一个简单的TCP客户端,可以连接到本地服务器,发送消息,并接收服务器的响应。它使用了基本的套接字编程技术,包括创建套接字、连接服务器、发送和接收数据以及关闭套接字。程序通过一个无限循环来持续接收用户输入,并在输入"end"时退出。

 

这两段代码分别实现了一个简单的 TCP 客户端和一个 TCP 服务器。

 TCP 服务器代码解释

这段代码实现了一个 TCP 服务器,它在本地计算机的 6000 端口上监听来自客户端的连接请求。

1. **创建套接字**:
   - 使用 `socket` 函数创建一个 TCP 套接字 `sockfd`。

2. **绑定地址**:
   - 使用 `bind` 函数将套接字绑定到本地地址 `127.0.0.1` 和端口 `6000` 上。这样,服务器就准备好在指定的地址和端口上监听客户端的连接请求。

3. **监听连接**:
   - 使用 `listen` 函数使套接字进入监听状态,等待客户端的连接请求。监听队列的大小设置为 5,这意味着服务器可以同时处理最多 5 个未处理的连接请求。

4. **接受连接**:
   - 使用 `accept` 函数接受客户端的连接请求。每当有新的客户端连接时,`accept` 函数会返回一个新的套接字 `c`,用于与该客户端进行通信。

5. **处理客户端请求**:
   - 使用 `fork` 创建一个新的子进程来处理每个客户端的请求。这样,服务器可以同时处理多个客户端的连接。
   - 在子进程中,使用 `recv` 函数接收客户端发送的数据,并使用 `send` 函数发送响应(在这个例子中,响应是字符串 "ok")。
   - 当客户端关闭连接或发生错误时,子进程会退出。

6. **关闭连接**:
   - 在父进程中,关闭与客户端的连接套接字 `c`。

 TCP 客户端代码解释

这段代码实现了一个 TCP 客户端,它连接到本地服务器(127.0.0.1:6000),发送消息,并接收服务器的响应。

1. **创建套接字**:
   - 使用 `socket` 函数创建一个 TCP 套接字 `sockfd`。

2. **连接到服务器**:
   - 使用 `connect` 函数连接到服务器的地址 `127.0.0.1` 和端口 `6000` 上。

3. **发送和接收数据**:
   - 进入一个无限循环,提示用户输入消息。
   - 使用 `fgets` 函数从标准输入读取用户输入的消息。
   - 如果用户输入 "end",则退出循环,关闭连接并退出程序。
   - 使用 `send` 函数将用户输入的消息发送到服务器。
   - 使用 `recv` 函数接收服务器的响应,并使用 `printf` 函数打印响应。

4. **关闭连接**:
   - 在退出循环后,关闭与服务器的连接套接字 `sockfd`。

### 总结

这两段代码实现了一个简单的 TCP 客户端-服务器通信模型:

- **服务器**:在本地计算机的 6000 端口上监听客户端的连接请求,使用多进程模型来处理每个客户端的请求。服务器接收客户端发送的数据,并发送 "ok" 作为响应。
- **客户端**:连接到本地服务器,发送用户输入的消息,并接收服务器的响应。

这种模型可以用于实现各种基于 TCP 的网络应用程序,如聊天程序、文件传输等。

会出现僵死进程,所以需要加入信号的使用来解决僵死进程

三、TCP(传输控制协议)的状态转换图

展示了TCP连接从建立到关闭的整个过程中可能经历的各种状态。

2.1 状态

1. **CLOSED**:初始状态,表示连接尚未建立。
2. **LISTEN**:服务器在该状态监听来自客户端的连接请求。
3. **SYN_SENT**:客户端发送SYN请求连接,等待服务器确认。
4. **SYN_RCVD**:服务器收到SYN请求后,发送SYN+ACK响应,进入此状态,等待客户端的确认。
5. **ESTABLISHED**:双方确认连接后,连接建立,可以开始传输数据。
6. **FIN_WAIT_1**:主动关闭连接的一方发送FIN请求,希望关闭连接。
7. **FIN_WAIT_2**:在FIN_WAIT_1状态下收到对方的ACK后,进入此状态,等待对方的FIN请求。
8. **CLOSING**:双方同时发送FIN请求,等待对方的ACK。
9. **TIME_WAIT**:主动关闭连接的一方在发送FIN请求并收到对方的ACK后,进入此状态,等待一段时间以确保对方收到ACK。
10. **CLOSE_WAIT**:被动关闭连接的一方收到FIN请求后,进入此状态,等待应用程序关闭连接。
11. **LAST_ACK**:被动关闭连接的一方发送FIN请求后,等待对方的ACK。

2.2 转换

1. **被动打开**:服务器从CLOSED状态进入LISTEN状态,等待客户端的连接请求。
2. **主动打开**:客户端从CLOSED状态发送SYN请求,进入SYN_SENT状态。
3. **连接建立**:
   - 客户端发送SYN请求,进入SYN_SENT状态。
   - 服务器收到SYN请求,发送SYN+ACK响应,进入SYN_RCVD状态。
   - 客户端收到SYN+ACK响应,发送ACK确认,进入ESTABLISHED状态。
   - 服务器收到ACK确认,进入ESTABLISHED状态。
4. **数据传输**:在ESTABLISHED状态下,双方可以进行数据传输。
5. **连接关闭**:
   - 主动关闭的一方发送FIN请求,进入FIN_WAIT_1状态。
   - 被动关闭的一方收到FIN请求,发送ACK确认,进入CLOSE_WAIT状态。
   - 被动关闭的一方发送FIN请求,进入LAST_ACK状态。
   - 主动关闭的一方收到FIN请求,发送ACK确认,进入TIME_WAIT状态。
   - TIME_WAIT状态持续一段时间后,连接关闭,进入CLOSED状态。 

TCP连接的建立和关闭是一个复杂的过程,涉及到多个状态和状态转换。连接建立需要三次握手(SYN, SYN+ACK, ACK),而连接关闭需要四次挥手(FIN, ACK, FIN, ACK)。这种设计确保了连接的可靠性和数据的完整性。

在Linux系统中使用netstat命令查看网络连接状态的输出结果。netstat是一个常用的网络工具,用于显示网络连接、路由表、接口统计等信息。图片中的命令netstat -nat用于显示所有网络连接和监听端口,包括TCP和UDP协议,并且不解析服务名称

  1. 输出字段

    • Proto:协议类型,如TCP或TCP6。

    • Recv-Q:接收队列长度。

    • Send-Q:发送队列长度。

    • Local Address:本地地址和端口。

    • Foreign Address:远程地址和端口。

    • State:连接状态,如LISTEN、ESTABLISHED、CLOSE_WAIT等。

    • PID/Program name:进程ID和程序名称。

  2. 状态解释

    • LISTEN:端口正在监听,等待连接请求。

    • ESTABLISHED:连接已建立,数据可以传输。

    • CLOSE_WAIT:被动关闭连接的一方等待关闭连接。

    • FIN_WAIT_1:主动关闭连接的一方等待对方的FIN请求。

    • FIN_WAIT_2:主动关闭连接的一方等待对方的ACK确认。

    • TIME_WAIT:主动关闭连接的一方等待一段时间以确保对方收到ACK。

  • 第一张图显示了多个端口处于LISTEN状态,表示这些端口正在等待连接请求。

  • 第二张图显示了一个端口(127.0.0.1:6000)已经完成了三次握手,处于ESTABLISHED状态,表示连接已经建立。

  • 第三张图显示了一个端口(127.0.0.1:6000)处于CLOSE_WAIT状态,表示被动关闭连接的一方等待关闭连接。

变成time wait端口被占用 状态服务器不能启动

为什么需要time wait状态? 

1. 可靠的终止TCP连接

TCP 连接的终止需要通过四次挥手过程来完成。在主动关闭连接的一方发送了 FIN 报文后,它需要等待对方的 ACK 报文。然而,由于网络延迟或其他原因,这个 ACK 报文可能会丢失或延迟到达。如果主动关闭方在发送 FIN 报文后立即关闭,那么它将无法接收到这个 ACK 报文,从而导致连接没有被正确关闭。

为了避免这种情况,主动关闭方会进入 TIME_WAIT 状态,等待一段时间(通常是 2 倍的 MSL,即 Maximum Segment Lifetime,报文段的最大生存时间)。这段时间足够长,可以确保即使 ACK 报文丢失或延迟,主动关闭方也能够接收到来自对方的重传 ACK 报文,从而可靠地终止连接。

2. 保证让迟来的TCP报文段有足够的时间被识别并丢弃

TCP 连接的标识是由源 IP 地址、目的 IP 地址、源端口号和目的端口号共同组成的。当一个 TCP 连接被关闭后,这些标识可能会被新的连接所使用。然而,由于网络延迟或其他原因,旧连接的报文段可能会在连接关闭后仍然存在于网络中。

如果新的连接使用了相同的标识,那么这些迟来的旧报文段可能会被错误地识别为新连接的报文段,从而导致数据混乱。TIME_WAIT 状态通过等待一段时间,确保所有旧的报文段都已经被丢弃或过期,从而避免这种情况的发生。

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

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

相关文章

探秘 Ruby 与 JavaScript:动态语言的多面风采

1 语法特性对比&#xff1a;简洁与灵活 1.1 Ruby 的语法优雅 Ruby 的语法设计旨在让代码读起来像自然语言一样流畅。它拥有简洁而富有表现力的语法结构&#xff0c;例如代码块、符号等。 以下是一个使用 Ruby 进行数组操作的简单示例&#xff1a; # 定义一个数组 numbers [1…

点评项目回顾

表结构 基于Session实现登录流程 发送验证码&#xff1a; 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行保存&#xf…

OpenShift介绍,跟 Kubernetes ,Docker关系

1. OpenShift 简介 OpenShift是一个开源项目,基于主流的容器技术Docker及容器编排引擎Kubernetes构建。可以基于OpenShift构建属于自己的容器云平台。OpenShift的开源社区版本叫OpenShift Origin,现在叫OKD。 OpenShift 项目主页:https://www.okd.io/。OpenShift GitHub仓库…

Ubuntu服务器性能调优指南:从基础工具到系统稳定性提升

一、性能监控工具的三维应用 1.1 监控矩阵构建 通过组合工具搭建立体监控体系&#xff1a; # 实时进程监控 htop --sort-keyPERCENT_CPU# 存储性能采集 iostat -dx 2# 内存分析组合拳 vmstat -SM 1 | awk NR>2 {print "Active:"$5"MB Swpd:"$3"…

计算机视觉——基于MediaPipe实现人体姿态估计与不良动作检测

概述 正确的身体姿势是个人整体健康的关键。然而&#xff0c;保持正确的身体姿势可能会很困难&#xff0c;因为我们常常会忘记。本博客文章将逐步指导您构建一个解决方案。最近&#xff0c;我们使用 MediaPipe POSE 进行身体姿势检测&#xff0c;效果非常好&#xff01; 一、…

LSTM结合LightGBM高纬时序预测

1. LSTM 时间序列预测 LSTM 是 RNN&#xff08;Recurrent Neural Network&#xff09;的一种变体&#xff0c;它解决了普通 RNN 训练时的梯度消失和梯度爆炸问题&#xff0c;适用于长期依赖的时间序列建模。 LSTM 结构 LSTM 由 输入门&#xff08;Input Gate&#xff09;、遗…

六、adb通过Wifi连接

背景 收集是荣耀X40,数据线原装全新的&#xff0c;USB连上之后&#xff0c;老是断&#xff0c;电脑一直叮咚叮咚的响个不停&#xff0c;试试WIFI 连接是否稳定&#xff0c;需要手机和电脑用相同的WIFI. 连接 1.通过 USB 连接手机和电脑(打开USB调试等这些都略过) adb device…

如何理解前端开发中的“换皮“

"换皮"在前端开发中是一个常见的术语&#xff0c;通常指的是在不改变网站或应用核心功能和结构的情况下&#xff0c;只改变其外观和视觉表现。以下是关于前端"换皮"的详细理解&#xff1a; 基本概念 定义&#xff1a;换皮(Skinning)是指保持应用程序功能不…

从 Vue 到 React:深入理解 useState 的异步更新

目录 从 Vue 到 React&#xff1a;深入理解 useState 的异步更新与函数式写法1. Vue 的响应式回顾&#xff1a;每次赋值立即生效2. React 的状态更新是异步且批量的原因解析 3. 函数式更新&#xff1a;唯一的正确写法4. 对比 Vue vs React 状态更新5. React useState 的核心源码…

使用Redis实现分布式限流

一、限流场景与算法选择 1.1 为什么需要分布式限流 在高并发系统中&#xff0c;API接口的突发流量可能导致服务雪崩。传统的单机限流方案在分布式环境下存在局限&#xff0c;需要借助Redis等中间件实现集群级流量控制。 1.2 令牌桶算法优势 允许突发流量&#xff1a;稳定速…

快速搭建WordPress网站的主题

WP快主题(wpkuai.com )是一款由知名WordPress专业团队打造的专业化WordPress主题&#xff0c;旨在让用户使用该wordpress主题快速搭建网站。 WP快主题专注于快速搭建WordPress网站的主题解决方案。其主题设计注重简洁性与高效性&#xff0c;旨在帮助用户快速完成网站的搭建和部…

STM32江科大----------PID算法

声明&#xff1a;本人跟随b站江科大学习&#xff0c;本文章是观看完视频后的一些个人总结和经验分享&#xff0c;也同时为了方便日后的复习&#xff0c;如果有错误请各位大佬指出&#xff0c;如果对你有帮助可以点个赞小小鼓励一下&#xff0c;本文章建议配合原视频使用❤️ 如…

将JSON格式的SQL查询转换为完整SQL语句的实战解析

一、背景与需求 在现代数据处理中,JSON格式因其灵活性和可读性,常被用于定义SQL查询的结构。然而,直接编写JSON格式的SQL指令后,如何将其转换为可执行的SQL语句是开发者常遇到的挑战。本文将通过一个Python函数和多个实际案例,解析如何将JSON结构转换为完整的SQL语句,并…

java CountDownLatch用法简介

CountDownLatch倒计数锁存器 CountDownLatch&#xff1a;用于协同控制一个或多个线程等待在其他线程中执行的一组操作完成&#xff0c;然后再继续执行 CountDownLatch用法 构造方法&#xff1a;CountDownLatch(int count)&#xff0c;count指定等待的条件数&#xff08;任务…

Leetcode - 双周赛135

目录 一、3512. 使数组和能被 K 整除的最少操作次数二、3513. 不同 XOR 三元组的数目 I三、3514. 不同 XOR 三元组的数目 II四、3515. 带权树中的最短路径 一、3512. 使数组和能被 K 整除的最少操作次数 题目链接 本题实际上求的就是数组 nums 和的余数&#xff0c;代码如下&…

【后端】【python】利用反射器----动态设置装饰器

&#x1f4d8; Python 装饰器进阶指南 一、装饰器本质 ✅ 本质概念 Python 装饰器的本质是 函数嵌套 返回函数&#xff0c;它是对已有函数的增强&#xff0c;不修改原函数代码&#xff0c;使用语法糖 decorator 实现包裹效果。 def my_decorator(func):def wrapper(*args, …

Nodejs Express框架

参考&#xff1a;Node.js Express 框架 | 菜鸟教程 第一个 Express 框架实例 接下来我们使用 Express 框架来输出 "Hello World"。 以下实例中我们引入了 express 模块&#xff0c;并在客户端发起请求后&#xff0c;响应 "Hello World" 字符串。 创建 e…

Docker Swarm 集群

Docker Swarm 集群 本文档介绍了 Docker Swarm 集群的基本概念、工作原理以及相关命令使用示例&#xff0c;包括如何在服务调度中使用自定义标签。本文档适用于需要管理和扩展 Docker 容器化应用程序的生产环境场景。 1. 什么是 Docker Swarm Docker Swarm 是用于管理 Docker…

充电宝项目中的MQTT(轻量高效的物联网通信协议)

文章目录 补充&#xff1a;HTTP协议MQTT协议MQTT的核心特性MQTT vs HTTP&#xff1a;关键对比 EMQX项目集成EMQX集成配置客户端和回调方法具体接口和方法处理处理类 补充&#xff1a;HTTP协议 HTTP是一种应用层协议&#xff0c;使用TCP作为传输层协议&#xff0c;默认端口是80…

【iOS】UIPageViewController学习

UIPageViewController学习 前言创建一个UIPageViewController最简单的使用 UIPageViewController的方法说明&#xff1a;效果展示 UIPageViewController的协议方法 前言 笔者最近在写项目时想实现一个翻书效果&#xff0c;上网学习到了UIPageViewController今天写本篇博客总结…