【Linux深入浅出】之全连接队列及抓包介绍
【Linux深入浅出】之全连接队列及抓包介绍
- 理解listen系统调用函数的第二个参数
- 简单实验
- 实验目的
- 实验设备
- 实验代码
- 实验现象
- 全连接队列简单理解
- 什么是全连接队列
- 全连接队列的大小
- 从Linux内核的角度理解虚拟文件、sock、网络三方的关系
- 回顾虚拟文件部分的知识
- struct socket结构体介绍
- struct tcp_sock与struct udp_sock介绍
- struct tcp_sock
- struct inet_connection_sock结构体
- struct inet_sock结构体
- 总结
- struct udp_sock
- Tcp接收缓冲区与发送缓冲区
- 分层介绍
- tcp抓包介绍
- Linux中使用tcp dump进行抓包并分析tcp过程
- tcp dump的安装
- tcp dump的简单使用
- 实验
- windows中使用wireshark进行抓包
- wireshark的安装
- 使用telnet作为客户端访问云服务器上的服务器程序
- 设置wireshark过滤规则
- 使用wireshark进行抓包
理解listen系统调用函数的第二个参数
listen
函数是在进行TCP socket
编程时的系统调用函数,它的功能是将普通套接字设置为监听状态,也就是将普通的套接字变成监听套接字,以便它能收到来自客户端的连接请求。
第一个参数是我们之前创建的socket
描述符,那么第二个参数应该如何理解呢?直接输出结论:backlog规定了全连接队列的最大长度,全连接队列是用于维护三次握手成功但是系统来不及接收的连接,backlog+1
是这个队列的长度。
简单实验
实验目的
下面我们将做一个小实验,这个实验主要会验证如下几个点:
- 三次握手成功建立连接,并不需要
accept
的参与,因为它是系统自动完成的,accept
只是负责从全连接队列中取走已经建立好的连接。 - backlog+1 = 全连接队列的长度。
因为accept
函数会取走全连接队列中的连接,而且我们的实验就是模拟系统非常忙的情况,所以 TCP server端是不需要调用accept
函数的。
实验设备
虚拟机一台,云服务器一台。
在同一台设备上会影响实验效果,因为TCP连接是双向的,从服务器->客户端,客户端->服务器都会维护一个连接,所以如果在一台设备上做实验,会有干扰。
实验代码
-
TcpServer.cc
:#include <iostream> #include <string> #include <cerrno> #include <cstring> #include <cstdlib> #include <memory> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <unistd.h>const static int default_backlog = 1;enum {Usage_Err = 1,Socket_Err,Bind_Err,Listen_Err };#define CONV(addr_ptr) ((struct sockaddr *)addr_ptr)class TcpServer { public:TcpServer(uint16_t port) : _port(port), _isrunning(false){}// 都是固定套路void Init(){// 1. 创建socket, file fd, 本质是文件_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){exit(0);}int opt = 1;setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));// 2. 填充本地网络信息并bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = htonl(INADDR_ANY);// 2.1 bindif (bind(_listensock, CONV(&local), sizeof(local)) != 0){exit(Bind_Err);}// 3. 设置socket为监听状态,tcp特有的if (listen(_listensock, default_backlog) != 0){exit(Listen_Err);}}void ProcessConnection(int sockfd, struct sockaddr_in &peer){uint16_t clientport = ntohs(peer.sin_port);std::string clientip = inet_ntoa(peer.sin_addr);std::string prefix = clientip + ":" + std::to_string(clientport);std::cout << "get a new connection, info is : " << prefix << std::endl;while (true){char inbuffer[1024];ssize_t s = ::read(sockfd, inbuffer, sizeof(inbuffer)-1);if(s > 0){inbuffer[s] = 0;std::cout << prefix << "# " << inbuffer << std::endl;std::string echo = inbuffer;echo += "[tcp server echo message]";write(sockfd, echo.c_str(), echo.size());}else{std::cout << prefix << " client quit" << std::endl;break;}}}void Start(){_isrunning = true;while (_isrunning){sleep(1);}}~TcpServer(){}private:uint16_t _port;int _listensock; // TODObool _isrunning; };using namespace std;void Usage(std::string proc) {std::cout << "Usage : \n\t" << proc << " local_port\n"<< std::endl; } // ./tcp_server 8888 int main(int argc, char *argv[]) {if (argc != 2){Usage(argv[0]);return Usage_Err;}uint16_t port = stoi(argv[1]);std::unique_ptr<TcpServer> tsvr = make_unique<TcpServer>(port);tsvr->Init();tsvr->Start();return 0; }
-
TcpClient.cc
:#include <iostream> #include <string> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> #include <netinet/in.h>int main(int argc, char **argv) {if (argc != 3){std::cerr << "\nUsage: " << argv[0] << " serverip serverport\n"<< std::endl;return 1;}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (clientSocket < 0){std::cerr << "socket failed" << std::endl;return 1;}sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(serverport); // 替换为服务器端口serverAddr.sin_addr.s_addr = inet_addr(serverip.c_str()); // 替换为服务器IP地址int result = connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));if (result < 0){std::cerr << "connect failed" << std::endl;::close(clientSocket);return 1;}while (true){std::string message;std::cout << "Please Enter@ ";std::getline(std::cin, message);if (message.empty())continue;send(clientSocket, message.c_str(), message.size(), 0);char buffer[1024] = {0};int bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);if (bytesReceived > 0){buffer[bytesReceived] = '\0'; // 确保字符串以 null 结尾std::cout << "Received from server: " << buffer << std::endl;}else{std::cerr << "recv failed" << std::endl;}}::close(clientSocket);return 0; }
实验现象
-
验证:即使服务器端没有调用
accpet
函数,三次握手也能建立连接成功:- 结论:
accept
系统调用函数并不参与三次握手,它只负责从下层取走连接(socket文件描述符)。
- 结论:
-
验证
Tcp
全连接最多维护backlog+1
个连接:
- 可以看到,我们在虚拟机中同时运行了多个
TcpClient
客户端,但最终只有两个成功建立连接,这是因为全连接的大小不够了所以不会接收来自客户端的连接,只有上层调用accept
拿走在全连接队列中已经建立的连接,全连接的空间才会腾出来。
全连接队列简单理解
什么是全连接队列
全连接队列就是我们内核(传输层)中某个结构体中维护的一个队列,每一个listen
套接字都有一个全连接队列:
在Linux内核中所谓的连接和全连接队列都是struct
结构体,后面我们会结合Linux内核重点介绍。
- 注意:全连接队列的大小并不是代表TcpServer服务器只能同时处理这么多,而是表示它来不及处理(来不及调用
accept
)的连接的最大数量。
全连接队列的大小
全连接队列的本质其实是生产者消费者模型,全连接队列作为生产者一直生产连接,而上层的accept
作为消费者一直从全连接队列中取走连接。
全连接队列的大小不能太大,也不能太小:
- 如果backlog为0:会增加服务器的闲置率,如果有全连接队列,那么可能只需要等待一会,服务器就有空闲可以把连接取走处理了,如果
backlog
为0,直接就是三次握手建立不成功,用户就以为你的服务已经崩溃,短时间内就不会访问了。 - 如果backlog过大:那么处于全连接队列结尾的用户就可能需要等待很久来能享受到服务,这样用户体验不好,还不如直接连接失败,而且维护连接也会占用内存,用多余的内存去给服务器处理数据可能效率更高。
过去,常用的默认值可能是5或者50左右,但是现代Linux系统的默认值通常要高得多。
通常这个值有一个上限,我的Linux系统中为4096:
/proc/sys/net/core/somaxconn
:这个内核参数定义了系统范围内每个端口的最大监听队列长度。它设置了listen()
函数中backlog
参数的上限值。tcp_max_syn_backlog
:这个文件中规定的是未完成连接请求的最大数量(半连接队列)。
从Linux内核的角度理解虚拟文件、sock、网络三方的关系
回顾虚拟文件部分的知识
我们都知道在运行服务器程序后,系统会给这个进程创建一个task_struct
结构体,它是用来描述进程的,这个结构体中又会有一个file_struct*
的指针,它指向了一个file_struct
的对象,这个file_struct
结构体是用来管理打开的文件的,它里面有一个文件描述符表,这个文件描述符表中的每一个下标都指向struct file*
对象。
但是我们的网络socket
是怎么和struct file
这个结构体挂上联系的呢?这是我们今天要解决的问题之一,因为文件描述表中的文件描述符不仅仅有普通文件的还有网络套接字文件。
struct socket结构体介绍
struct socket {socket_state state;unsigned long flags;struct proto_ops *ops;struct fasync_struct *fasync_list;struct file *file;struct sock *sk;wait_queue_head_t wait;short type;unsigned char passcred;
};
struct socket
结构体是我们网络socket的入口,它是一个通用的套接字类型。
-
short type
:表示套接字的类型,是流式套接字还是数据报式的套接字: -
struct proto_ops *ops
:它是一个保存各种函数方法的类型,可以通过type
字段让其指向不同的方法。 -
struct file*
:指向虚拟文件层的struct file
对象,但是我们不是需要通过socket
文件描述符找到struct socket
嘛,怎么顺序反过来,别担心,其实struct file
对象中也有一个开放字段是可以指向struct socket
对象的,它就是void*
类型的private_data
字段。
所以经过对struct socket
结构体的学习,我们上面的图可以继续完善:
并且调用socket
系统调用的同时就创建了struct socket
、struct file
并在文件描述表中申请了空间,然后还让struct socket
与struct file
互相指向。
那Tcp Socket
与Udp Socket
岂不是没有区别了,既然调用socket
都会创建struct socket
的话,别急,我们继续往下学习。
struct tcp_sock与struct udp_sock介绍
struct tcp_sock
tcp_sock
结构体中有很多关于tcp
的字段,譬如:
int tcp_header_len
:即将要发送的TCP报文的头部的长度,以字节为单位。rcv_nxt, snd_nxt
: 分别表示期望接收的下一个序列号和发送方即将发送的下一个序列号。snd_ssthresh, snd_cwnd
: 慢启动阈值和拥塞窗口大小,是拥塞控制的重要参数。
但我们更想知道,它的第一个字段struct inet_connection_sock
是什么:
struct inet_connection_sock inet_conn;
:光看其名称,这个结构体肯定与连接有关。
struct inet_connection_sock结构体
这个结构体是描述的TCP与连接相关的属性,里面包括了全连接队列。全连接队列中不仅维护三次握手已经建立好的连接,也会维护只进行了二次或者一次的半连接,但是半连接的生命周期一般很短。
-
struct request_sock_queue icsk_accept_queue;
:这个字段就是我们之前一直在谈的全连接队列,它由listen
sock维护,用于管理监听套接字上的半连接(SYN_RCVD状态)和全连接(ESTABLISHED状态但未被accept()接受)队列。
但我们最好奇的是它的第一个属性字段:
struct inet_sock inet
:这是一个struct inet_sock
类型的成员,包含了通用的因特网套接字信息。tcp_sock
以此为基础,添加TCP特定的信息。
struct inet_sock结构体
struct inet_sock
结构体中存储的是与网络通信相关的信息,例如:
_u32 daddr
:外部IPv4地址。_u32 rcv_saddr
:本地IPv4地址。_u32 dport
:目的端口号。
我们进行Tcp
网络通信,调用bind
系统调用函数bind
IP地址和端口号,不就是在往这个struct inet_sock
结构体中写数据吗?
我们惊奇的发现这个inet_sock
结构体的第一个字段的类型居然是struct sock
,我们之前不是在struct socket
里面见过这个字段吗,让struct socket
指向它,不就可以通过通用套接字访问到Tcpsock
了吗?
所以我们预测udp_sock
中一定也存在struct sock
字段,而且一定是在最前面。
总结
看了这么多结构体,我们可以画图总结一下它们的关系了:
后续只需要通过socket
中的struct sock*
字段,通过强制类型转化,我们就可以访问到struct sock
、struct inet_sock
、struct inet_connection_sock
、struct tcp_sock
结构体的内容,因为它们的初始地址都是相同的,这样通过结构体嵌套,我们就实现了C风格的多态。
那么当我们客户端和服务器经过三次握手后,建立了一个新的连接,内核会帮助我们做哪些事情呢?
-
最最重要的是创建
struct inet_connection_sock
,这表示一个新的连接,里面的inet_sock
字段存储着这个连接相关的属性字段(IP地址、端口号)。 -
然后就是
struct tcp_sock
对象,三次握手完成,内核实际上已经为这个新建立的连接创建了完整的struct tcp_sock
结构体。它不仅包含了inet_connection_sock
中的所有字段,还添加了许多TCP特有的属性和方法,例如序列号管理、窗口缩放、重传机制等。每当一个新的TCP连接被接受(即完成了三次握手),就会创建一个tcp_sock
实例来管理这个连接的状态和行为。 -
除此之外,内核还会将这个连接(队尾的
next
的struct sock*
指向新连接的struct sock
)加入listen
套接字的全连接队列中(做类似链表的操作),然后需要将队列的元素个数加1。
内核中会有实现上述功能的方法:
如果全连接队列中没有空间了,三次握手根本就不会完成,也就不会创建上述的结构体。
当调用accept
函数时,它会做如下事情:
-
创建
struct socket
对象(三次握手完成时并没有创建这个通用的套接字类型),然后从全连接队列中取出队头连接的struct sock*
,然后赋值给struct socket
的struct sock*
变量,就相当与让struct socket
指向了struct tcp_sock
,因为struct tcp_sock
的最开始的字段是struct sock*
。 -
创建
struct file
,并在文件描述符表中开辟一个新的空间指向这个struct file
对象。 -
最后,让
struct file
与struct socket
互相引用。 -
返回文件描述符给上层。
内核中的方法
sock_map_fd
就是实现类似功能的。
自此之后,我们就可以通过socket fd
找到struct file
,然后通过struct file
中的private_data
字段找到struct socket
对象,而通用套接字的sk
又指向struct tcp_sock
的首地址空间的struct sock
对象。然后通过强制类型转换,可以访问tcp
这个连接相关的任何信息,包括报文、拥塞控制属性、滑动窗口属性、确认应答相关属性(序号、确认序号)。
struct udp_sock
由于udp
协议比tcp
协议要简单,所以udp_sock
结构体的字段也要少一些。
而且由于udp
是无连接的协议,所以它没有连接相关的字段,它的第一个结构体对象就直接是struct inet_sock
结构体。这和tcp
的inet_sock
是一样的,因为网络套接字部分两者有很多相同的部分,所以可以复用。
对于udp_sock
就是这样:
Tcp接收缓冲区与发送缓冲区
我们前面不是一直谈到TCP存在接收缓冲区和发送缓冲区吗?它们在内核中是否有体现呢?
当然有,在struct sock
结构体中,存在着这两个字段:
它们就是接收缓冲区与发送缓冲区,每个连接都有单独的struct sock
,也就意味着有单独的接收缓冲区与发送缓冲区。
sk_buff_head
是这个缓冲区的类型,它是一个类似队列的结构体:
struct sk_buff
是描述报文的,也就是解析出来或者即将发送的应用层的报文:
分层介绍
自此之后,虚拟文件、socket、网络三者的关系我们就清楚了,我们也清楚了如何通过文件描述符找到关于套接字的各种信息。
它们自上而下是有层次的,可以分为虚拟文件层、通用套接字层和网络套接字层。其中通用套接字就像是一个基类,它提供了一种通用的方式来创建各种类型的套接字,但是当网络真的建立起来,又会有其它细微的不同。
tcp抓包介绍
Linux中使用tcp dump进行抓包并分析tcp过程
tcp dump的安装
ubuntu下:
sudo apt update
sudp apt install -y tcpdump
通过检查版本号验证是否安装成功:
tcpdump --version
tcp dump的简单使用
-
捕获所有网络接口中的报文:
sudo tcpdump -i any tcp
-i
:interface是接口的意思,any代表任何,-i any
的意思就是捕获所以网络接口中的报文。tcp
:只捕获tcp
报文。
-
捕获指定网络接口的报文:
sudo tcpdump -i [本机某网络接口名称] tcp
我们可以通过命令
ifconfig
查看本主机的所有网络接口: -
捕获指定源IP的报文:
sudo tcpdump src host 192.168.0.1 and tcp
上述命令的含义是:捕获源IP地址为
192.168.0.1
的到达本主机的tcp
报文:-
现在的一般后端服务器都会使用反向代理来实现负载均衡技术,在大型应用或服务中,通常会部署多个反向代理服务器以提高性能、增加可用性和提供冗余。所以可能就会出现多次
ping qq.com
这个相同的域名,得到来自不同公网IP服务器的回复,这也不用惊讶,所以上面的实验存在一定的运气的成分。- 上面的显示的
公网IP
可能是反向代理服务器的IP地址,而不是后端服务真正的公网IP。
- 上面的显示的
-
-
捕获指定目的IP地址的报文:
sudo tcpdump dst host 192.168.0.1 and tcp
上面命令的含义是捕获目的IP地址为
192.168.0.1
的tcp
报文:-
注意这个目的IP为什么是
iZt8qyfqyfs47mZ
呢?云服务提供商使用类似的随机字符串作为实例ID或设备标识:你也可以去云服务网站的控制台修改这个实例名称。
-
但是如果我们希望它显示
IP
地址,而不是显示云服务器的实例名称该怎么办呢?加上选项-n
即可:
-
-
捕获特定端口号的
TCP
报文:-
使用
port
关键字可以捕获特定端口号的报文,例如捕获80
端口的TCP报文(通常是http请求):sudo tcpdump port 80 and tcp
-
实验
使用tcpdump
工具,一般以捕获特定端口的形式居多,代码和上述的验证listen
系统调用函数的第二个参数的代码一样,简单的tcp echo
服务器:
-
服务器不给客户端发送数据,也不
accept
接受连接:-
将客户端在虚拟机上运行,观察抓包现象:
-
三次握手:
- 因为三次握手是没有发送数据的,所以
length
为0。
- 因为三次握手是没有发送数据的,所以
-
当我们虚拟机客户端给服务器发送数据报文,但是服务器收到该报文,发送的
ack
报文数据为0,没有发送数据报文,我们有理由相信,服务器根本没有将这个连接拿上来给用户,但是三次握手肯定成功了,并且ack
报文是OS自动发送的,不需要用户参与:- 看了一下代码果然没有将连接拿上来。
-
-
-
将
accept
函数注释取消后继续实验:-
三次握手部分(依旧正常):Flags中的
S
代表SYN
标志位,win
是窗口大小(用于滑动窗口中确定窗口大小),可以看到双方还协商了mss
的大小。 -
服务器接收数据,发送数据:
现在收发数据都正常了。
-
四次挥手部分,客户端主动退出:
-
就只有客户端给服务器发送了
FIN
报文,服务器OS自动给它回复了一个ACK
报文,服务器并没有断开连接,我们有理由相信,服务器端忘记close
关闭socket
描述符了。
-
-
-
服务器端在客户端关闭连接后也要正常关闭连接,修改代码后继续测试四次挥手的过程:
-
不是说四次挥手吗,为什么只有三次呢,我们有理由相信,在客户端给服务器发送
FIN
报文后,服务器立马就给客户端发送了FIN
报文,并且这个时间和系统自动发送ACK
报文的时间几乎是同时,所以触发了捎带应答,如果我们让服务器sleep
上1s再关闭socketfd
,就可以看到四次挥手: -
sleep
后的结果:
-
windows中使用wireshark进行抓包
wireshark的安装
wireshark-4.4.3-x64.exe
下载好之后,直接安装即可,没有太多要注意的地方。
使用telnet作为客户端访问云服务器上的服务器程序
默认windows上telnet服务是没有打开的,我们可以手动打开,打开telnet教程
设置wireshark过滤规则
-
首先选择你想捕获哪个网卡的流量(上行和下行):
-
选择好之后,顶部工具栏点捕获,点开始,就可以开始捕获该网卡的流量:
-
默认是捕获经过该网络接口的流量:
-
在顶部可以设置过滤规则,我们设置
ip
为服务器ip
,只关心服务器所在的端口号8888
:ip.addr == 121.40.68.117 && tcp.port == 8888
顶部过滤栏是绿色说明语法没有问题:
使用wireshark进行抓包
-
启动服务器程序:
-
启动windows上的
telnet
服务:telnet [服务器公网ip] [端口号]
- 进入这个界面就代表启动成功了。
-
观察报文:
-
三次握手:
-
telnet
发送1字节的数据:点击某一个包,下面可以看到更详细的信息:
-
-
四次挥手,telnet输入
ctrl ]
进入命令行模式,然后点quit
就可退出:
红色的报文为超时重传。
相关文章:
【Linux深入浅出】之全连接队列及抓包介绍
【Linux深入浅出】之全连接队列及抓包介绍 理解listen系统调用函数的第二个参数简单实验实验目的实验设备实验代码实验现象 全连接队列简单理解什么是全连接队列全连接队列的大小 从Linux内核的角度理解虚拟文件、sock、网络三方的关系回顾虚拟文件部分的知识struct socket结构…...
Linux C++ JNI封装、打包成jar包供Java调用详细介绍
在前面 Android专栏 中详细介绍了如何在Android Studio中调用通过jni封装的c库。 在Android使用 opencv c代码,需要准备opencv4android,也就是c的任何代码,是使用Android NDK编译的,相当于在windows/mac上使用Android stdido交叉…...
CPO-BP+NSGA,豪冠猪优化BP神经网络+多目标遗传算法!(Matlab完整源码和数据)
目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.CPO-BPNSGA,豪冠猪优化BP神经网络多目标遗传算法!(Matlab完整源码和数据),豪冠猪算法优化BP神经网络的权值和阈值,运行环境Matlab2020b及以上…...
组件通信-v-model
概述:实现 父↔子 之间相互通信。 前序知识 —— v-model的本质 <!-- 使用v-model指令 --> <input type"text" v-model"userName"><!-- v-model的本质是下面这行代码 --> <input type"text" :value"use…...
使用PyMongo连接MongoDB的基本操作
MongoDB是由C语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储形式类似JSON对象,它的字段值可以包含其他文档、数组及文档数组。在这一节中,我们就来回顾Python 3下MongoDB的存储操作。 常用命令:…...
010302-oss_反向代理_负载均衡-web扩展2-基础入门-网络安全
文章目录 1 OSS1.1 什么是 OSS 存储?1.2 OSS 核心功能1.3 OSS 的优势1.4 典型使用场景1.5 如何接入 OSS?1.6 注意事项1.7 cloudreve实战演示1.7.1 配置cloudreve连接阿里云oss1.7.2 常见错误1.7.3 安全测试影响 2 反向代理2.1 正向代理和反向代理2.2 演示…...
PyQt 或 PySide6 进行 GUI 开发文档与教程
一、官网文档 Qt 官方文档:Porting to Qt 6 | Qt 6.9Qt 维基:Qt WikiQt for Python (PySide6) :Qt for Python - Qt WikiPySide6 快速上手指南:Getting Started - Qt for Python PyS…...
【东枫科技】AMD / Xilinx Alveo™ V80计算加速器卡
AMD / Xilinx Alveo™ V80计算加速器卡 AMD/Xilinx Alveo ™ V80计算加速器卡是一款功能强大的计算加速器,基于7nm Versal™ 自适应SoC架构而打造。 AMD/Xilinx Alveo V80卡设计用于内存密集型任务。 这些任务包括HPC、数据分析、网络安全、传感器处理、计算存储和…...
C++ 动态内存管理
operator new和operator delete函数是两个全局函数,编译器在编译new和delete时会调用这两个函数,其底层分别是封装malloc和free 1.new new 内置类型 内置类型没有构造函数,所以使用new就是调operator new函数开空间,如果要初始化…...
(11)Vue-Router路由的详细使用
本系列教程目录:Vue3Element Plus全套学习笔记-目录大纲 文章目录 第2章 路由 Vue-Router2.1 Vue路由快速入门2.1.1 创建项目2.1.2 路由运行流程 2.2 传递参数-useRoute2.2.1 路径参数-params1)普通传参2)传递多个参数3)对象方式传…...
RISCV的smstateen-ssstateen扩展
RISC-V 的 Smstateen / Ssstateen 扩展是为了解决安全性和资源隔离性问题而设计的,尤其是针对在多个上下文(如用户线程、多个虚拟机)之间 潜在的隐蔽信道(covert channel) 风险。 🌐 背景:隐蔽信道与上下文切换问题 当…...
C++ 与 Lua 联合编程
在软件开发的广阔天地里,不同编程语言各有所长。C 以其卓越的性能、强大的功能和对硬件的直接操控能力,在系统开发、游戏引擎、服务器等底层领域占据重要地位,但c编写的程序需要编译,这往往是一个耗时操作,特别对于大型…...
瑞萨 EZ-CUBE2 调试器
瑞萨 EZ-CUBE2 调试器 本文介绍了瑞萨 EZ-CUBE2 调试器的基本信息、调试方式、环境搭建、硬件连接、软件测试等。 包装展示 调试器展示 开关选项 详见:EZ-CUBE2 | Renesas 瑞萨电子 . 环境搭建 使用 Renesas 公司的 e2 studio 开发工具,下载 并安装该…...
MATLAB滤波工具箱演示——自定义维度、滤波方法的例程演示与绘图、数据输出
使用 M A T L A B MATLAB MATLAB的界面做了一个 M A T L A B MATLAB MATLAB滤波工具箱 d e m o demo demo,本文章给出演示:自定义维度、滤波方法的例程演示与绘图、数据输出 文章目录 编辑界面使用方法优势待改进点部分代码 编辑界面 使用 M A T L A B …...
数据库索引优化实战: 如何设计高效的数据库索引
数据库索引优化实战: 如何设计高效的数据库索引 一、理解数据库索引的核心原理 1.1 B树索引的结构特性 数据库索引(Database Index)的本质是通过特定数据结构加速数据检索。现代关系型数据库普遍采用B树(B Tree)作为默认索引结构&…...
TS 安装
TS较JS优势 1 TS静态类型编程语言。编译时发现错误 2 类型系统 强化变量类型概念 3 支持新语法 4 类型推断机制 可以和React框架中的各种hook配合 5 任何地方都有代码提示 tsc 命令 将TS转为JS 1 tsc 文件.ts 生成 js文件 2 执行JS代码...
CMake separate_arguments用法详解
separate_arguments 是 CMake 中用于将字符串分割成参数列表的命令,适用于处理包含空格的参数或复杂命令行参数。以下是其用法详解: 基本语法 separate_arguments(<variable> [UNIX|WINDOWS_COMMAND] [PROGRAM <program>] [ARGS <args&…...
【AI科技】AMD ROCm 6.4 新功能:突破性推理、即插即用容器和模块化部署,可在 AMD Instinct GPU 上实现可扩展 AI
AMD ROCm 6.4 新功能:突破性推理、即插即用容器和模块化部署,可在 AMD Instinct GPU 上实现可扩展 AI 现代 AI 工作负载的规模和复杂性不断增长,而人们对性能和部署便捷性的期望也日益提升。对于在 AMD Instinct™ GPU 上构建 AI 和 HPC 未来…...
2025年- H20-Lc128-240. 搜索二维矩阵 II(矩阵)---java版
1.题目描述 2.思路 遍历矩阵,然后如果遇到矩阵中的值正好等于target,输出true。否则,输出false。 3.代码 public class H240 {public boolean searchMatrix(int[][] matrix, int target) {//1.计算出总的行值,总的列值。int mm…...
LearningFlow:大语言模型城市驾驶的自动化策略学习工作流程
《LearningFlow: Automated Policy Learning Workflow for Urban Driving with Large Language Models》2025年1月发表,来自香港科技大学广州分校的论文。 强化学习(RL)的最新进展表明了自动驾驶的巨大潜力。尽管有这一前景,但奖励…...
C语言数据类型与内存布局
C语言数据类型内存占用 类型32位系统64位系统格式说明符char1字节1字节%cint4字节4字节%dfloat4字节4字节%fdouble8字节8字节%lflong long8字节8字节%lld...
从原理到实战讲解回归算法!!!
哈喽,大家好,我是我不是小upper, 今天系统梳理了线性回归的核心知识,从模型的基本原理、参数估计方法,到模型评估指标与实际应用场景,帮助大家深入理解这一经典的机器学习算法,助力数据分析与预测工作。 …...
linux指令中的竖线(“|”)是干啥的?【含实例展示】
文章目录 一、管道符的基本概念二、管道符的核心作用三、常用实例展示四、进阶技巧五、注意事项总结 实操展示**案例1:统计日志中特定错误的数量****案例2:查找当前运行的进程****案例3:合并排序并去重****案例4:实时监控CPU占用前…...
[HOT 100] 0124. 二叉树中的最大路径和
文章目录 1. 题目链接2. 题目描述3. 题目示例4. 解题思路5. 题解代码6. 复杂度分析 1. 题目链接 124. 二叉树中的最大路径和 - 力扣(LeetCode) 2. 题目描述 二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一…...
[SoC]AXI总线Performance验证方案
AXI总线Performance验证方案 测试 AXI (Advanced eXtensible Interface) 的性能是 SoC 验证中的重要任务,旨在评估其在不同负载和配置下的表现是否满足设计要求。以下详细说明如何测试 AXI 的性能、需要统计的变量、计算方法、在验证环境中动态计算性能的方法,以及如何…...
EMC PowerStore存储学习之一NVMe磁盘的命名规则
PowerStore的日志中经常会看到类似于/dev/nvme1n1的磁盘,在svc_diag list --show_drives中也可以看到类似这样的输出,如下图: 这里的Drives的显示都是 /dev/nvmeXnY的形式,那么这个磁盘命名规则怎么解读呢? 在Linux系…...
apt-mirror搭建ubuntu本地离线源
参考资料 4 Steps to Setup Local Repository in Ubuntu using APT-mirror 使用 APT-mirror 四步配置 Ubuntu 本地软件仓库 ubuntu下的apt-get内网本地源的搭建...
【记录】新Ubuntu20配置voxelmap的环境安装
因为系统总出问题,仅用于个人纪录。 1. 升级CMake到3.28及以上版本(Sophus依赖) wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh chmod x cmake-3.28.3-linux-x86_64.sh sudo ./cmake-3.2…...
Python全流程开发实战:基于IMAP协议安全下载个人Gmail邮箱内所有PDF附件
在日常办公场景中,面对成百上千封携带PDF附件的邮件,手动逐一下载往往耗时耗力,成为效率瓶颈。如何通过代码实现“一键批量下载”?本文将以**“Gmail全量PDF附件下载工具”**开发为例,完整拆解从需求分析到落地交付的P…...
CPU:AMD的线程撕裂者(Threadripper)和霄龙(EPYC)的区别
AMD的**线程撕裂者(Threadripper)和霄龙(EPYC)**虽然都是面向高性能市场的处理器,但它们在定位、功能和技术规格上有显著区别。以下是两者的主要差异: 1. 目标市场 线程撕裂者(Threadripper&…...
【五一培训】Day 2
注: 1. 本次培训内容的记录将以“Topic”的方式来呈现,用于记录个人对知识点的理解。 2. 由于培训期间,作者受限于一些现实条件,本文的排版及图片等相关优化,需要过一段时间才能完成。 3. 关于老板点评的一些思考 你…...
shell_plus
python manage.py shell_plus 是由 django-extensions 提供的一个增强版的 Django shell,它自动导入你的所有模型和其他一些便捷功能,使得交互式开发更加方便。 如果你遇到配置或运行问题,特别是与 RQ_SHOW_ADMIN_LINK 相关的 ImproperlyCon…...
基于C++、JsonCpp、Muduo库实现的分布式RPC通信框架
⭐️个人主页:小羊 ⭐️所属专栏:RPC框架 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 项目介绍JsonCpp库简单介绍Muduo库简单介绍C11异步操作——std::future1. 使用 std::async 关联异步任务2. std::packaged_task…...
Redis TLS 加密对性能的影响分析
Redis TLS 加密对性能的影响分析 是的,Redis 启用 TLS 加密确实会对性能产生一定影响,但影响程度取决于多种因素。以下是详细分析: 一、性能影响的主要来源 加密/解密开销: TLS 握手过程中的非对称加密(如 RSA、…...
树与二叉树完全解析:从基础到应用
目录 一、树形结构的基础认知 1.1 树的定义与特点 1.2 核心术语解析 二、二叉树的深度解析 2.1 二叉树定义 2.2 特殊二叉树类型 2.3 重要性质总结 三、二叉树的存储与遍历 3.1 存储方式对比 3.2 遍历算法精讲 四、经典题型训练 4.1 相同树判断(LeetCode…...
PostgreSQL:pgJDBC 下载和安装
PostgreSQL 的 pgJDBC 是用于 Java 程序连接和操作 PostgreSQL 数据库的 JDBC 驱动程序。 PostgreSQL:pgJDBC v42.7 下载和安装 点击【Application Stack Builder】 安装目录: 运行 cmd cd D:\PostgreSQL\pgJDBC copy postgresql-42.7.2.jar D:\groovy-…...
正则表达式与文本三剑客grep、sed、awk
目录 一、正则表达式 1.1、字符匹配 1.2、次数匹配 1.3、位置锚定 1.4、分组或其他 二、扩展正则表达式 三、grep 四、awk 4.1、常用命令选项 4.2、工作原理 4.3、基础用法 4.4、内置变量 4.5、模式 4.6、条件判断 4.7、awk中的循环语句 4.8、数组 4.9、脚本 …...
(35)VTK C++开发示例 ---将图片映射到平面2
文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容👉内容导航 👈👉VTK开发 👈 1. 概述 与上一个示例不同的是,使用vtkImageReader2Factory根据文件扩展名或内容自动创建对应的图像文件读取器&a…...
每日一题洛谷P8635 [蓝桥杯 2016 省 AB] 四平方和c++
P8635 [蓝桥杯 2016 省 AB] 四平方和 - 洛谷 (luogu.com.cn) 直接暴力枚举,不做任何优化的话最后会TLE一个,稍微优化一下就过了(数据给的还是太良心了) 优化:每层循环用if判断一下,如果大于n就直接跳 当然…...
【python】【UV】一篇文章学完新一代 Python 环境与包管理器使用指南
🐍 UV:新一代 Python 环境与包管理器使用指南 一、UV 是什么? UV 是由 Astral 团队开发的高性能 Python 环境管理器,旨在统一替代 pyenv、pip、venv、pip-tools、pipenv 等工具。 1.1 UV 的主要功能 🚀 极速包安装&…...
6.10.单源最短路径问题-Dijkstra算法
一.BFS算法的局限性: 如上图,BFS算法可以解决无权图的单源最短路径问题, 如果是解决带权图的单源最短路径问题,BFS算法就不适用了,如下图: 如上图,比如求G港到其他顶点的最短路径, …...
Python基于深度学习的网络舆情分析系统(附源码,部署)
大家好,我是Python徐师兄,一个有着7年大厂经验的程序员,也是一名热衷于分享干货的技术爱好者。平时我在 CSDN、掘金、华为云、阿里云和 InfoQ 等平台分享我的心得体会。 🍅文末获取源码联系🍅 2025年最全的计算机软件毕…...
mysql--索引
索引作为一种数据结构,其用途是用于提升检索数据的效率。 分类 普通索引(INDEX):索引列值可重复 唯一索引(UNIQUE):索引列值必须唯一,可以为NULL 主键索引(PRIMARY KEY&a…...
【算法题】荷兰国旗问题[力扣75题颜色分类] - JAVA
一、题目 二、文字解释 1.1 前言 本题是经典的「荷兰国旗问题」,由计算机科学家 Edsger W. Dijkstra 首先提出。如同图中所示的荷兰国旗,其由红、白、蓝三色水平排列组成。在算法领域,该问题可类比为将一个由特定的三种元素(可…...
【数据结构】堆的完整实现
堆的完整实现 堆的完整实现GitHub地址前言堆的核心功能实现重温堆的定义堆结构定义1. 堆初始化与销毁2. 元素交换函数3. 堆化操作向上调整(子→父)向下调整(父→子) 4. 堆元素插入5. 堆元素删除6. 辅助功能函数堆的判空获取堆顶元…...
软考 系统架构设计师系列知识点之杂项集萃(51)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(50) 第80题 设三个煤场A1、A2、A3分别能供应煤7、12、11万吨,三个工厂B1、B2、B3分别需要10、10、10万吨,从各煤场到各工厂运煤的单价(百元/吨&…...
patch命令在代码管理中的应用
patch 是一个用于将差异文件(补丁)应用到源代码的工具,常用于修复 bug、添加功能或调整代码结构。在您提供的代码中,patch 命令通过一系列补丁文件(.patch)修改了 open-amp 库的源代码。 patch 命令的核心作…...
Qt结构体运算符重载指南
在 Qt 中,结构体(struct)或类(class)中重载运算符是一种常见的做法,用于实现自定义类型的逻辑操作(如比较、算术运算等)。以下是一些常见的运算符重载示例和注意事项: 1.…...
基于bert预训练模型的垃圾短信分类系统
文章目录 任务介绍数据说明注意事项数据处理数据准备数据集划分数据集类构建模型构建与训练模型构建模型训练模型推理附录任务介绍 随着移动通信技术的飞速发展,短信(Short Message Service, SMS)已成为人们日常生活中不可或缺的沟通方式之一。然而,垃圾短信(Spam SMS)的…...
[Android] 网易爆米花TV 2.0.0.0429(原网易Filmly,支持多网盘的TV版、电脑版带海报墙播放器)
[Android] 网易爆米花 链接:https://pan.xunlei.com/s/VOPDuQS9D7qixvAnoy7-he2PA1?pwdhzvh# [Android] 网易爆米花TV 2.0.0.0429(原网易Filmly,支持多网盘的TV版、电脑版带海报墙播放器) 详细介绍直接上主页截图,…...