嵌入式Linux学习笔记(5)-进程间常见通讯方式(c语言实现)
一、概述
进程间通信(IPC,InterProcess Communication)是指在多个进程之间进行数据传输和共享的机制。在操作系统中,进程是运行中的程序的实例,每个进程都有自己的内存空间和资源。
进程间通信可以用于在不同的进程之间传递数据、共享资源、进行协同工作等。常见的进程间通信方式有以下几种:
-
管道(Pipe):管道是一种半双工的通信方式,它是通过创建一个管道文件用于两个进程之间的通信。一个进程可以将数据写入管道,而另一个进程可以从管道中读取数据。
-
有名管道(Named Pipe):有名管道也是一种管道,不同之处在于它是一个带有名称的管道,可以用于多个进程之间的通信。
-
共享内存(Shared Memory):共享内存是一种进程间通信的高效方式,它允许多个进程访问同一块内存区域,从而实现数据共享。
-
消息队列(Message Queue):消息队列是一种按照先进先出(FIFO)原则进行数据传输的机制。进程可以将消息放入队列,而其他进程可以从队列中读取消息。
-
信号量(Semaphore):信号量是一个特殊的变量,用于控制多个进程之间的临界区访问。通过信号量可以实现进程的互斥和同步操作。
-
套接字(Socket):套接字是一种网络编程中常用的进程间通信方式,它可以在不同的主机之间进行数据传输和通信。
二、管道
1、用法
管道(pipe)是一种在进程间通信中非常常用的机制,它可以将一个进程的输出(stdout)直接作为另一个进程的输入(stdin)。
pipe()函数:创建管道使用,它的原型为:
int pipe(int pipefd[2]);
该函数需要传入一个整型的数组,数组的长度必须是2。该函数会创建一个管道,并将管道的读写句柄分别存储在pipefd[0]和pipefd[1]中。pipefd[0]用于读取管道中的数据,pipefd[1]用于写入管道。
常用函数有:
read()函数:从管道中读取数据。其原型为:
ssize_t read(int fd, void *buf, size_t count);
其中,fd是管道的读取句柄(即pipefd[0]),buf是存储读取数据的缓冲区,count是读取的最大字节数。该函数返回实际读取的字节数。如果从终端读取数据,fd 的值为 STDIN_FILENO。
write()函数:向管道中写入数据。其原型为:
ssize_t write(int fd, const void *buf, size_t count);
其中,fd是管道的写入句柄(即pipefd[1]),buf是待写入的数据的缓冲区,count是待写入的字节数。该函数返回实际写入的字节数。如果往终端写入数据,fd 的值为 STDOUT_FILENO。
close()函数:关闭管道的读取或写入端。其原型为:
int close(int fd);
其中,fd是待关闭的管道的句柄。
2、用例
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>int main(int argc, char const *argv[])
{pid_t pid;int pipefd[2];if (argc != 2){fprintf(stderr,"%s: 参数不够!\n",argv[0]);exit(EXIT_FAILURE);}//创建管道if (pipe(pipefd) == -1){perror("创建管道数据");exit(EXIT_FAILURE);}//创建子进程pid = fork();if (pid < 0){fprintf(stderr,"%s: 邀请新学员失败!\n",argv[0]);exit(EXIT_FAILURE);}else if (pid == 0){//读取管道数据并打印close(pipefd[1]);char str[100]={0};sprintf(str,"%d 读出数据",getpid());write(STDOUT_FILENO,&str,sizeof(str));char buf;while (read(pipefd[0],&buf,1)>0){write(STDOUT_FILENO,&buf,1);}write(STDOUT_FILENO,"\n",1);close(pipefd[0]);_exit(EXIT_SUCCESS);//直接退出不做任何操作}else{//写入管道数据,提供给子进程close(pipefd[0]);printf("%d 写入数据\n",getpid());write(pipefd[1],argv[1],strlen(argv[1]));close(pipefd[1]);waitpid(pid,NULL,0);}return 0;
}
这个用例创建了一个子进程。随后父进程写入数据,子进程读取数据。
三、有名管道
1、用法
有名管道(Named Pipe)是一种在操作系统中用于进程间通信的通道。它可以在不相关的进程之间传递数据。以下是对有名管道及常用函数的详细介绍。
有名管道是一种特殊的文件,它以文件名的形式存在于文件系统中。与普通文件不同的是,有名管道允许不相关的进程之间进行通信。有名管道是以FIFO(先进先出)的方式传递数据,即先进入管道的数据首先被读取出来。有名管道可以用于在父进程和子进程之间传递数据,也可以用于不同进程之间的通信。
mkfifo()
:创建一个新的有名管道。它的原型为:
int mkfifo(const char *pathname, mode_t mode)
其中,pathname
是管道的路径名,mode
定义了管道的权限。该函数成功时返回0,失败时返回-1。
open()
:打开有名管道以进行读取或写入操作。它的原型为:
int open(const char *pathname, int flags)
其中,pathname
是管道的路径名,flags
定义了打开的方式和权限。该函数成功时返回文件描述符,失败时返回-1。
其余函数如:read,write,close与管道用法一致。
有名管道提供了一种简单的进程间通信方式,但也有一些限制。首先,它只适用于在同一计算机上的进程间通信。其次,有名管道是阻塞式的,即读取操作会一直等待直到有数据可读,写入操作会一直等待直到有空间可写。因此,在使用有名管道时要注意避免进程间出现死锁的情况。
2、用例
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>int main(int argc, char const *argv[])
{int fd;//有名管道创建完可重复使用,但推荐每次用完删除,下次重新创建char *pipe_path = "/tmp/myfifo";if(mkfifo(pipe_path,0644) != 0){perror("mkfifo");if (errno != 17)//不是文件已存在{exit(EXIT_FAILURE);}}fd = open(pipe_path,O_WRONLY);if(fd == -1){perror("open");exit(EXIT_FAILURE);}char buf[100];ssize_t read_num;//从终端写入数据到管道中while ((read_num = read(STDIN_FILENO,buf,100)) > 0){write(fd,buf,read_num);}if (read_num < 0){perror("read");close(fd);exit(EXIT_FAILURE);}printf("发送数据到管道完成,进程终止\n");close(fd);//清除管道//清除对应特殊文件if (unlink(pipe_path) == -1){perror("unlink");}return 0;
}
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>int main(int argc, char const *argv[])
{int fd;char *pipe_path = "/tmp/myfifo";// if(mkfifo(pipe_path,0644) != 0){// perror("mkfifo");// exit(EXIT_FAILURE);// }fd = open(pipe_path,O_RDONLY);if(fd == -1){perror("open");exit(EXIT_FAILURE);}char buf[100];ssize_t read_num;//读取管道信息while ((read_num = read(fd,buf,100)) > 0){write(STDOUT_FILENO,buf,read_num);}if (read_num < 0){perror("read");close(fd);exit(EXIT_FAILURE);}printf("接收管道数据完成,进程终止\n");close(fd);return 0;
}
两个.c文件分别代表两个无关联的进程。一个从终端接收数据并将数据写入有名管道中,另一个从管道中接收数据并打印在终端。
四、共享内存
1、用法
在C语言中,进程间通信(IPC)是实现不同进程之间数据交换和共享的重要方式之一。共享内存是一种高效的IPC机制,可以实现不同进程之间的数据共享。
共享内存是一块由操作系统管理的内存区域,可以被多个进程同时访问。进程可以将共享内存映射到自己的地址空间中,从而可以直接读写该内存区域,实现数据共享。
shm_open():该函数用于创建或打开一个共享内存对象。它的原型如下:
int shm_open(const char *name, int oflag, mode_t mode);
参数:
name:共享内存对象的名称
oflag:打开标志,用于指定打开方式和操作权限
mode:权限位,用于指定该共享内存对象的操作权限
返回值:共享内存对象的文件描述符,若打开或创建失败则返回-1。
shm_unlink():该函数用于删除一个共享内存对象。它的原型如下:
int shm_unlink(const char *name);
参数:
name:共享内存对象的名称
返回值:成功返回0,失败返回-1。
mmap():该函数用于将共享内存映射到进程的地址空间中。它的原型如下:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数:
addr:指定映射的起始地址,通常设为NULL,让操作系统自动选择一个合适的地址。
length:映射的长度,单位为字节。
prot:映射内存区域的保护模式,如读、写、执行等。
flags:映射的标志,用于指定映射方式和映射类型。
fd:共享内存对象的文件描述符。
offset:共享内存对象中的偏移量。
返回值:映射成功时返回映射区域的起始地址,失败时返回MAP_FAILED。
munmap
():函数用于释放由mmap
函数映射的内存区域。它的原型如下:
int munmap(void *addr, size_t length);
参数:
addr
:指向要释放的内存区域的起始地址。这个地址必须是mmap
返回的地址,或者是页面大小的整数倍。
length
:要释放的内存区域的大小。
返回值:成功时,返回0;失败时,返回-1,并设置errno
。
2、用例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>int main(int argc, char const *argv[])
{char *share;// 1.创建共享内存对象char shm_name[100]={0};sprintf(shm_name,"/letter%d",getpid());int fd;fd = shm_open(shm_name,O_RDWR | O_CREAT,0644);if (fd < 0){perror("shm_open");exit(EXIT_FAILURE);}// 2.设置共享内存对象大小ftruncate(fd,1024);// 3.内存映射share = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if (share == MAP_FAILED){perror("mmap");exit(EXIT_FAILURE);}// 映射后关闭fd,不是释放close(fd);// 4.使用内存映射实现进程间的通讯pid_t pid = fork();if (pid < 0){perror("fork");exit(EXIT_FAILURE);}else if (pid == 0){strcpy(share,"hello,my name is liuyuhui\n");printf("子进程%d:发送完毕!\n",getpid());}else{waitpid(pid,NULL,0);printf("父进程 %d 接收到了子进程 %d 发送的消息: %s\n",getpid(),pid,share);// 5.释放映射区int re = munmap(share,1024);if (re == -1){perror("munmap");exit(EXIT_FAILURE);}}// 6.释放共享内存对象shm_unlink(shm_name);return 0;
}
共享内存大致就分了这六步。这个例程实现的是父进程向共享内存中写入数据,子进程从共享内存中读出数据。
五、消息队列
1、用法
在C语言中,进程间通讯是指两个或多个进程之间进行数据交换或共享资源的过程。消息队列是一种进程间通讯的方式,允许进程通过发送和接收消息来交换数据。
mq_open():用于创建或打开一个消息队列。函数原型如下:
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
参数:
name:消息队列的名称。
oflag:打开标志。可以是O_CREAT(如果消息队列不存在,则创建)和O_EXCL(与O_CREAT一起使用,确保创建新的消息队列)。
mode:权限和创建文件时的权限位掩码(只有在创建消息队列时才使用)。attr:指向消息队列属性的指针。
mq_unlink():用于删除一个已经命名的消息队列。函数原型如下:
int mq_unlink(const char *name);
参数:
name:消息队列的名称。
clock_gettime():用于获取当前时间。函数原型如下:
int clock_gettime(clockid_t clk_id, struct timespec *tp);
clk_id:时钟ID,可以是CLOCK_REALTIME(系统实时时间)或CLOCK_MONOTONIC(运行时间)。
tp:保存时间的结构体指针。
mq_timedsend():用于向消息队列发送消息,并可以设置发送超时时间。函数原型如下:
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
参数:
mqdes:消息队列描述符。
msg_ptr:指向发送消息的指针。
msg_len:发送消息的长度。
msg_prio:消息的优先级。
abs_timeout:绝对时间,若超过该时间则发送超时。
mq_timedreceive():用于从消息队列接收消息,并可以设置接收超时时间。函数原型如下:
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);
参数:
mqdes:消息队列描述符。
msg_ptr:指向接收消息的指针。
msg_len:接收消息的最大长度。
msg_prio:接收到的消息的优先级。
abs_timeout:绝对时间,若超过该时间则接收超时
2、用例
①:父子进程间通讯
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{struct mq_attr attr;attr.mq_maxmsg=10;attr.mq_msgsize=100;attr.mq_flags=0;attr.mq_curmsgs=0;//创建消息队列char *mq_name = "/father_son"; mqd_t mqdes = mq_open(mq_name,O_RDWR|O_CREAT,0644,&attr);if (mqdes == -1){perror("mq_open");exit(EXIT_FAILURE);}//创建进程pid_t pid = fork();if (pid < 0){perror("fork");exit(EXIT_FAILURE);}else if (pid == 0){//子进程接收消息char read_buf[100];struct timespec time_info;//接受数据for (int i = 0; i < 10; i++){//清空并发送数据memset(read_buf,0,100);//设置等待时间clock_gettime(0,&time_info);time_info.tv_sec += 15;//接收消息if(mq_timedreceive(mqdes,read_buf,100,NULL,&time_info) == -1){perror("mq_timedreceive");}printf("子进程接收到消息:%s\n",read_buf);}}else{//父进程发送消息char send_buf[100];struct timespec time_info;for (int i = 0; i < 10; i++){//清空并发送数据memset(send_buf,0,100);sprintf(send_buf,"父进程发送的第 %d 条消息\n",(i+1));//获取当前时间clock_gettime(0,&time_info);time_info.tv_sec += 5;//发送消息if(mq_timedsend(mqdes,send_buf,strlen(send_buf),0,&time_info) == -1){perror("mq_timedsend");}printf("父进程休息1s\n");sleep(1);}} //释放两次消息队列的引用close(mqdes);//清除一次消息队列if (pid > 0){mq_unlink(mq_name);}return 0;
}
②:不同进程间通讯
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{struct mq_attr attr;attr.mq_maxmsg=10;attr.mq_msgsize=100;attr.mq_flags=0;attr.mq_curmsgs=0;//创建消息队列char *mq_name = "/p_c_mq"; mqd_t mqdes = mq_open(mq_name,O_RDWR|O_CREAT,0644,&attr);if (mqdes == -1){perror("mq_open");exit(EXIT_FAILURE);}char write_buf[100];struct timespec time_info;//不断接收控制台消息 发送到消息队列while (1){memset(write_buf,0,100);ssize_t read_count = read(STDIN_FILENO,write_buf,100);clock_gettime(0,&time_info);time_info.tv_sec += 5;if (read_count == -1){perror("read");continue;}else if (read_count == 0){//ctrl + d 退出时printf("EOF,exit...\n");char eof = EOF;if (mq_timedsend(mqdes,&eof,1,0,&time_info) == -1){perror("mq_timedsend");}break;}//正常发送if (mq_timedsend(mqdes,write_buf,strlen(write_buf),0,&time_info) == -1){perror("mq_timedsend");}printf("正常发送成功!\n");}//释放消息队列描述符close(mqdes);//清除消息队列 (消费者执行一次即可)// mq_unlink(mq_name);return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{struct mq_attr attr;attr.mq_maxmsg=10;attr.mq_msgsize=100;attr.mq_flags=0;attr.mq_curmsgs=0;//创建消息队列char *mq_name = "/p_c_mq"; mqd_t mqdes = mq_open(mq_name,O_RDWR|O_CREAT,0644,&attr);if (mqdes == -1){perror("mq_open");exit(EXIT_FAILURE);}char read_buf[100];struct timespec time_info;//不断接收控制台消息 发送到消息队列while (1){memset(read_buf,0,100);clock_gettime(0,&time_info);time_info.tv_sec += 15;//正常接收if (mq_timedreceive(mqdes,read_buf,100,NULL,&time_info) == -1){perror("mq_timedreceive");}//判断是否结束if (read_buf[0] == EOF){printf("收到结束信息,准备退出...\n");break;}printf("正常接收成功,信息为:%s\n",read_buf);}//释放消息队列描述符close(mqdes);//清除消息队列mq_unlink(mq_name);return 0;
}
需要注意的是因为公用同一片资源,所以在不同进程间通讯时接收方只需接收完消息后将消息队列清除掉即可,发送方不需要重复清除,也可避免接收方还没读取完消息队列的值就被发送方清除了消息队列。
相关文章:

嵌入式Linux学习笔记(5)-进程间常见通讯方式(c语言实现)
一、概述 进程间通信(IPC,InterProcess Communication)是指在多个进程之间进行数据传输和共享的机制。在操作系统中,进程是运行中的程序的实例,每个进程都有自己的内存空间和资源。 进程间通信可以用于在不同的进程之间…...

【移动端】菜单的自动展开与收回
前言 为了满足手机上菜单栏随用户移动,菜单的自动展示与隐藏,特此记录 基本原理 实现逻辑 window.addEventListener(‘scroll’, debouncedScrollHandler) – 监听文档视图滚动事件 document.querySelector(‘.header’) – 选择器匹配元素 创建show和h…...

Java获取Object中Value的方法
在Java中,获取对象(Object)中的值通常依赖于对象的类型以及我们希望访问的属性。由于Java是一种静态类型语言,直接从一个Object类型中访问属性是不可能的,因为Object是所有类的超类,但它本身不包含任何特定…...

集群聊天服务器项目【C++】(二)Json的简单使用
在上一章中,简单介绍了本项目的内容、技术栈、需求和目标等,详细介绍了环境配置,如果还没有配置成功,请参考我的上一篇博客环境配置 今天主要介绍Json库是什么以及简单的使用。 1.为什么要使用Json 我们在网络传输数据时&#…...

班迪录屏和这三款录屏工具,一键操作,太方便了!
嘿,小伙伴们!今天我要跟大家分享几款超棒的录屏工具,它们绝对是我们在工作和学习中不可或缺的好帮;这些工具功能强大且操作简单,下面就让我来详细介绍一下它们的使用体验和好用之处吧! 班迪录屏工具使用体…...

DAY60Bellman_ford 算法
队列优化算法 请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。 如果能够从城市 1 到连通到城市 n, 请输出一个整数,表示运输成本。如果该整数是负数,则表示实现了盈利。如果从城市 1 没有路径可达城市…...

Dubbo SPI源码
文章目录 Dubbo SPI使用方式AOP功能源码剖析SPI注解1.获取加载器2.获取拓展实例对象3.创建拓展类的实例对象 Dubbo SPI Dubbo 的 SPI(Service Provider Interface)机制是一种强大的扩展机制,它允许开发者在运行时动态地替换或增加框架的功能。…...

《C++代码高度优化之双刃剑:避免过度优化引发的“暗雷”》
在 C编程的世界里,追求高效性能的代码是每个开发者的目标之一。高度优化的 C代码可以带来显著的性能提升,让程序在运行速度、内存占用等方面表现出色。然而,正如一把双刃剑,过度优化可能会引入难以察觉的错误,给程序带…...

javascript网页设计案例
设计一个具有良好用户体验的 JavaScript 网页涉及多个方面,如用户界面(UI)、用户体验(UX)、交互设计等。以下是一些示例案例,展示了如何使用 JavaScript 创建功能丰富且吸引人的网页设计。 1. 响应式导航菜…...

初阶数据结构【TOP】- 11.普通二叉树的介绍 - 1. (细致,保姆~~!)
文章目录 前言一、普通二叉树的链式结构二、 造树三、普通二叉树的遍历四、遍历完整代码五、总结 前言 本篇文章笔者将会对普通二叉树部分进行细致的讲解 , 本篇主要包括以下内容: 二叉树链式结构的介绍 ,二叉树的遍历. 笔者会一步一步分析带学者领略递归的美好~~ 一、普通二叉…...

【pyenv】pyenv安装版本超时的解决方案
目录 1、现象 2、分析现象 3、手动下载所需版本 4、存放到指定路径 5、重新安装 6、pip失败(做个记录,未找到原因) 7、方法二修改环境变量方法 7.1 设置环境变量 7.2 更新 7.3 安装即可 8、方法三修改XML文件 前言:研…...

【新片场-注册安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...

新160个crackme - 057-bbbs-crackme04
运行分析 因软件版本老旧,需使用windows XP虚拟机运行有个SystemID,值为12345678需破解User ID和Password PE分析 yC壳,32位 OD手动脱壳 使用windows XP虚拟机,将程序拖入OD按一下F8,ESP变红,根据ESP定律设…...

车机中 Android Audio 音频常见问题分析方法实践小结
文章目录 前言1. 无声2. 断音3. 杂音4. 延迟播放5. 焦点问题6. 无声问题(连上 BT )其他完善中…… 前言 本文主要总结了一下车机开发中遇到的 Audio 有关的问题,同时参考网上的一案例,由于Audio 模块出现音频问题的场景很多,对每一个出现的问…...

湘大 OJ 代码仓库
有时候不需要上传一些题解,想要上传一些纯代码就行,傻傻把代码上传到文章里面,感觉效率不是很高,还是建立一个代码仓库比较方便 需要会使用魔法可能才能访问,github代码仓库地址...

Ruoyi Cloud K8s 部署
本文视频版本:https://www.bilibili.com/video/BV1xF4Se3Esv 参考 https://blog.csdn.net/Equent/article/details/137779505 https://blog.csdn.net/weixin_48711696/article/details/138117392 https://zhuanlan.zhihu.com/p/470647732 https://gitee.com/y_project/Ruo…...

OpenGL Texture C++ Camera Filter滤镜
基于OpenGL Texture纹理的强大功能,在片段着色器(Shader)中编写GLSL代码,对YUV的数据进行数据转换从而实现视频编辑软件中的相机滤镜功能。 接上一篇OpenGL Texture C 预览Camera视频的功能实现,本篇来实现Camera滤镜效…...

基于Sobel算法的边缘检测设计与实现
1、边缘检测 针对的时灰度图像,顾名思义,检测图像的边缘,是针对图像像素点的一种计算,目的时标识数字图像中灰度变化明显的点,图像的边缘检测,在保留了图像的重要结构信息的同时,剔除了可以认为…...

java:练习
编写一个 Java 程序,计算并输出从 1 到用户指定的数字 n 中,所有“幸运数字”。幸运数字的定义如下:条件 1:数字的所有位数(如个位、十位)加起来的和是 7 的倍数。条件 2:数字本身是一个质数&am…...

大数据中一些常用的集群启停命令
文章目录 一、HDFS二、MapReduce && YARN三、Hive 一、HDFS 格式化namenode # 确保以hadoop用户执行 su - hadoop # 格式化namenode hadoop namenode -format启动 # 一键启动hdfs集群 start-dfs.sh # 一键关闭hdfs集群 stop-dfs.sh# 如果遇到命令未找到的错误&#…...

Golang、Python、C语言、Java的圆桌会议
一天,Golang、C语言、Java 和 Python 四位老朋友坐在编程领域的“圆桌会议”上,讨论如何一起完成一个任务:实现一个简单的高并发服务器,用于处理成千上万的请求。大家各抒己见,而 Golang 则是这次会议的主角。 1. Pyth…...

C语言编译原理
目录 一、C语言的编译过程 二、预处理 三、编译阶段 3.1 词法分析(Lexical Analysis) 3.2 语法分析(Syntax Analysis) 语法分析的主要步骤: 语法分析的关键技术: 构建AST: 符号表的维护…...

【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C 目录 前言 一、取地址运算符重载 1. const修饰成员函数 2. 取地址运算符重载 二、深究构造函数 三、类型转换 四、static修饰成员 1. static修饰成员变…...

Apache POI 学习
Apache POI 学习 1. 引言2. 环境搭建MavenGradle 3. 基础概念4. 基本操作4.1 创建 Excel 文件4.2 读取 Excel 文件 5. 进阶操作5.1 设置单元格样式5.2 数据验证5.3 图表创建5.4 合并单元格5.5 居中对齐5.6 设置边框和字体颜色 6. 性能优化7. 总结 1. 引言 Apache POI 是一个用…...

福建科立讯通信 指挥调度管理平台 SQL注入漏洞
北峰通信-福建科立讯通信 指挥调度管理平台 SQL注入漏洞 厂商域名和信息收集 域名: 工具sqlmap python sqlmap.py -u "http://ip:端口/api/client/down_file.php?uuid1" --batch 数据包 GET /api/client/down_file.php?uuid1%27%20AND%20(SELECT%20…...

4.qml单例模式
这里写目录标题 js文件单例模式qml文件单例模式 js文件单例模式 直接添加一个js文件到qml中 修改内容 TestA.qml import QtQuick 2.0 import QtQuick.Controls 2.12 import "./MyWork.js" as MWItem {Row{TextField {onEditingFinished: {MW.setA(text)}}Button…...

CACTI 0.8.7 迁移并升级到 1.2.7记录
升级前后环境 升级前: CactiEZ 中文版 V10 升级后: Ubuntu 2204 Cacti 1.2.7 升级原因:风险漏洞太多,升不尽,补不完. 升级流程 Created with Raphal 2.3.0 开始 DST:安装Ububtu/Mariadb/apache/php SRC:备份 DB/RRA 数据导入 结束 Cacti 依赖包 注意:UBUNTU下有些包,它非另外…...

OrionX vGPU 研发测试场景下最佳实践之Jupyter模式
在上周的文章中,我们讲述了OrionX vGPU研发测试场景下最佳实践之SSH模式,今天,让我们走进 Jupyter模式下的最佳实践。 • Jupyter模式:Jupyter是最近几年算法人员使用比较多的一种工具,很多企业已经将其改造集成开发工…...

国风编曲:了解国风 民族调式 五声音阶 作/编曲思路 变化音 六声、七声调式
中国风 以流行为基础加入中国特色乐器、调式、和声融为一体的风格 如:青花瓷、菊花台、绝代风华、江南等等等等 省流:中国风=流行民族乐 两者结合,民族元素越多越中国风 流行民族/摇滚民族/电子民族 注意:中国风≠…...

HTTP 响应状态码详解
HTTP状态码详解:HTTP状态码,是用以表示WEB服务器 HTTP响应状态的3位数字代码 小技巧: CtrlF 快速查找 Http状态码状态码含义100客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当…...