【Linux C | 网络编程】进程间传递文件描述符socketpair、sendmsg、recvmsg详解
我们的目的是,实现进程间传递文件描述符,是指 A进程打开文件fileA,获得文件描述符为fdA,现在 A进程要通过某种方法,传递fdA,使得另一个进程B,获得一个新的文件描述符fdB,这个fdB在进程B中的作用,跟fdA在进程A中的作用一样。即在 fdB上的操作,即是对fileA的操作。
可能很多人想到的是用管道pipe来实现,但是却没想象的那么容易。
1.了解fork函数
首先需要知道,在调用 fork()
函数之前打开的文件,其文件描述符会被复制到子进程中。这是因为在 fork()
函数执行时,操作系统会创建子进程,而子进程将复制父进程的地址空间,包括文件描述符表。因此,父进程打开的文件描述符会被子进程继承并复制到子进程的文件描述符表中。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>int main() {int file_fd;pid_t pid;char buf[1024];// 打开文件file_fd = open("file.txt", O_RDONLY);if (file_fd == -1) {perror("open");exit(EXIT_FAILURE);}// 创建子进程pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程ssize_t num_read;// 使用父进程打开的文件描述符操作文件while ((num_read = read(file_fd, buf, sizeof(buf))) > 0) {write(STDOUT_FILENO, buf, num_read);}if (num_read == -1) {perror("read");exit(EXIT_FAILURE);}close(file_fd); // 关闭文件描述符_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程int status;// 等待子进程结束wait(&status);// 关闭文件描述符close(file_fd);if (WIFEXITED(status)) {printf("子进程正常退出,退出状态码:%d\n", WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("子进程异常终止,信号编号:%d\n", WTERMSIG(status));}}return 0;
}
其次,在父进程调用 fork()
函数之后打开的文件,子进程不会自动继承这些新打开的文件描述符。也就是说,父进程在 fork()
之后打开的文件描述符,只在父进程的文件描述符表中有效,子进程不会获得这些文件描述符。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>int main() {int file_fd;pid_t pid;char buf[1024];// 创建子进程pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程printf("子进程开始...\n");// 尝试读取父进程在fork之后打开的文件描述符(这里没有实际的文件描述符,所以操作会失败)ssize_t num_read = read(3, buf, sizeof(buf)); // 假设文件描述符3是父进程在fork之后打开的if (num_read == -1) {perror("子进程无法读取文件(因为没有继承父进程在fork之后打开的文件描述符)");} else {write(STDOUT_FILENO, buf, num_read);}_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程int status;// 在fork之后打开文件file_fd = open("file.txt", O_RDONLY);if (file_fd == -1) {perror("open");exit(EXIT_FAILURE);}printf("父进程打开的文件描述符: %d\n", file_fd);// 等待子进程结束wait(&status);// 关闭文件描述符close(file_fd);if (WIFEXITED(status)) {printf("子进程正常退出,退出状态码:%d\n", WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("子进程异常终止,信号编号:%d\n", WTERMSIG(status));}}return 0;
}
结论:
- 在
fork()
之前打开的文件描述符,子进程会继承并可以使用。 - 在
fork()
之后打开的文件描述符,子进程不会继承,无法直接使用这些文件描述符。
2.使用管道pipe传递文件描述符的问题
下面是使用管道pipe传递文件描述符的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>#define BUF_SIZE 1024int main() {int pipe_fd[2]; // 管道的文件描述符数组int file_fd; // 文件的文件描述符pid_t pid;char buf[BUF_SIZE];// 创建管道if (pipe(pipe_fd) == -1) {perror("pipe");exit(EXIT_FAILURE);}// 创建子进程pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程close(pipe_fd[1]); // 关闭子进程不需要的写入端// 从管道中读取父进程传递的文件描述符int received_fd;read(pipe_fd[0], &received_fd, sizeof(int));printf("received_fd:%d\n", received_fd);// 使用接收到的文件描述符操作文件Assize_t num_read;while ((num_read = read(received_fd, buf, BUF_SIZE)) > 0) {write(STDOUT_FILENO, buf, num_read); // 在子进程中输出文件内容}if (num_read == -1) {perror("read");exit(EXIT_FAILURE);}close(received_fd); // 关闭文件描述符close(pipe_fd[0]); // 关闭管道读取端_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程close(pipe_fd[0]); // 关闭父进程不需要的读取端// 打开文件A并获取文件描述符file_fd = open("fileA.txt", O_RDONLY);if (file_fd == -1) {perror("open");exit(EXIT_FAILURE);}printf("file_fd:%d\n", file_fd);// 将文件描述符写入管道,传递给子进程if (write(pipe_fd[1], &file_fd, sizeof(int)) != sizeof(int)) {perror("write");exit(EXIT_FAILURE);}close(file_fd); // 关闭父进程中的文件描述符close(pipe_fd[1]); // 关闭管道写入端wait(NULL); // 等待子进程结束exit(EXIT_SUCCESS); // 退出父进程}
}
失败的原因:在代码中,父进程使用 write(pipe_fd[1], &file_fd, sizeof(int))
将 file_fd
写入管道的写入端。这一步骤本质上是将一个整数(文件描述符)写入到管道中。在Unix-like系统中,文件描述符是进程特定的,它们不能简单地通过整数值在不同的进程之间传递。直接通过管道传递文件描述符的整数值是无效的,因为文件描述符是相对于进程的。
要正确地传递文件描述符,必须使用sendmsg
和recvmsg
系统调用,以及SCM_RIGHTS
控制消息。这些系统调用允许在进程间传递文件描述符,而不仅仅是它们的整数值。
3.相关操作函数
3.1socketpair
函数
socketpair
函数用于在本地创建一对连接的套接字,通常用于同一主机上的进程间通信。它创建了一个双向通道,使得两个相关联的套接字可以在两个进程之间传递数据,实现全双工通信。socketpair
通常用于需要在同一台主机上的不同进程之间进行高效通信的场景。例如,父子进程间或者同一程序的不同线程之间。
#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
参数详解
domain:指定套接字的协议族,通常为 AF_UNIX(Unix 域套接字),用于本地进程间通信。
type:指定套接字的类型,常见的有:SOCK_STREAM:提供面向连接的、可靠的数据传输服务(如 TCP)。SOCK_DGRAM:提供无连接、不可靠的数据传输服务(如 UDP)。
protocol:指定套接字使用的协议,一般为 0,表示使用默认协议。
sv[2]:一个整型数组,用于存放创建的套接字对的文件描述符。在调用 socketpair 函数后,sv[0] 和 sv[1] 分别包含这两个相关联的套接字的文件描述符。
返回值:
成功时返回 0。
失败时返回 -1,并设置 errno 指示错误的类型。
3.2 sendmsg函数
sendmsg
函数用于向指定套接字发送消息,支持发送多块数据和控制消息(例如文件描述符)。
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
参数详解
sockfd:指定发送消息的套接字描述符。
msg:
指向 struct msghdr 结构体的指针,描述了要发送的消息的详细信息,包括数据块 (iovec 结构体数组) 和控制消息 (cmsghdr 结构体)。
flags:通常为 0,用于控制消息发送的附加选项。
返回值:
成功时返回发送的字节数。
失败时返回 -1,并设置 errno 指示错误的类型。
3.3 recvmsg函数
recvmsg
函数用于从指定套接字接收消息,支持接收多块数据和控制消息(例如文件描述符)。
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
参数详解
sockfd:指定接收消息的套接字描述符。
msg:
指向 struct msghdr 结构体的指针,用于存放接收到的消息的详细信息,包括数据块 (iovec 结构体数组) 和控制消息 (cmsghdr 结构体)。
flags:通常为 0,用于控制消息接收的附加选项。
返回值:
成功时返回发送的字节数。
失败时返回 -1,并设置 errno 指示错误的类型。
3.4 struct msghdr
结构体详解
struct msghdr {void *msg_name; // 指向目标地址的指针socklen_t msg_namelen; // 目标地址的长度struct iovec *msg_iov; // 数据块的数组size_t msg_iovlen; // 数据块数组的长度void *msg_control; // 控制消息的指针size_t msg_controllen; // 控制消息的长度int msg_flags; // 消息的标志
};
结构体成员:msg_name 和 msg_namelen:用于指定目标地址的信息,通常用于 UDP 套接字。msg_iov 和 msg_iovlen:用于指定数据块的数组和数组长度,支持数据的分散/聚集操作。msg_control 和 msg_controllen:用于处理控制消息(如文件描述符)的指针和长度。msg_flags:用于指定消息的标志,例如 MSG_DONTWAIT 等。struct iovec {void *iov_base; // 指向数据缓冲区的指针size_t iov_len; // 数据缓冲区的长度
};
成员解释:iov_base:指向数据缓冲区的指针,即存放数据的内存地址。iov_len:数据缓冲区的长度,即缓冲区中可以传输的数据的字节数。
-
工作原理:
sendmsg
函数通过msg
结构体描述要发送的数据块和控制消息。recvmsg
函数从套接字接收数据,并将接收到的数据填充到msg
结构体中指定的缓冲区中。
-
控制消息传递:
sendmsg
和recvmsg
支持通过msg_control
和msg_controllen
参数传递控制消息(cmsghdr
结构体),特别是用于传递文件描述符等特殊信息。
-
应用场景:
- 进程间通信(IPC):
sendmsg
和recvmsg
可以在进程间传递复杂的数据结构和文件描述符,适用于需要高效数据传输和资源共享的场景。 - 网络编程:在网络编程中,这两个函数用于向套接字发送数据和从套接字接收数据,支持分散/聚集操作和控制消息传递。
- 进程间通信(IPC):
作用:
struct iovec
结构体主要用于描述msg_iov
参数,即struct msghdr
结构体中的数据块数组。它允许用户指定多个数据块的位置和长度,从而实现数据的分散(scatter)和聚集(gather)操作。
3.5 writev 和 readv 函数
操作 struct iovec
结构体的系统调用主要用于实现数据的分散读(scatter)和聚集写(gather)操作,这些操作通常用于高效地传输多个数据块。
功能:
writev
函数将多个数据块从iov
指定的缓冲区中写入到文件描述符fd
所指定的文件中。readv
函数从文件描述符fd
所指定的文件中读取数据,并存储到iov
指定的多个缓冲区中。
#include <sys/uio.h>
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
参数:fd:文件描述符,表示要读写的文件。iov:指向 struct iovec 结构体数组的指针,描述要读写的数据块及其位置。iovcnt:iov 数组中元素的个数,即要读写的数据块的数量。
返回值:
成功时返回读写的字节数。
失败时返回 -1,并设置 errno 指示错误的类型。
-
工作原理:
writev
函数将iov
数组中描述的多个数据块依次写入到文件描述符fd
指定的文件中。readv
函数从文件描述符fd
指定的文件中读取数据,并将数据依次存储到iov
数组中指定的多个缓冲区中。
-
数据传输:
writev
和readv
函数支持数据的分散(scatter)和聚集(gather)操作,可以高效地处理多个非连续数据块的读写。
-
应用场景:
- 在网络编程中,
writev
和readv
可以用于同时发送或接收多个数据块,提高数据传输的效率。 - 在文件操作中,对于需要同时读写多个缓冲区数据的场景,如日志文件写入等,也可以使用这两个函数。
- 在网络编程中,
4.示例代码
将父进程中得到文件描述符传递给子进程,子进程得到该文件描述符同样可以操作该文件,实现文件描述符在进程间真正的传递。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>void send_fd(int socket, int fd_to_send) {struct msghdr msg = {0}; // 定义消息头结构体并初始化struct iovec iov[1]; // 定义数据块结构体数组struct cmsghdr *cmsg; // 定义控制消息头指针char control[CMSG_SPACE(sizeof(int))]; // 控制信息缓冲区char dummy = '*'; // 用于填充数据块的虚拟字符iov[0].iov_base = &dummy; // 设置数据块的基址为虚拟字符的地址iov[0].iov_len = 1; // 设置数据块的长度为1字节msg.msg_iov = iov; // 设置消息头的数据块数组msg.msg_iovlen = 1; // 设置数据块数组的长度msg.msg_control = control; // 设置消息头的控制信息msg.msg_controllen = sizeof(control); // 设置控制信息的长度cmsg = CMSG_FIRSTHDR(&msg); // 获取第一个控制消息头cmsg->cmsg_level = SOL_SOCKET; // 设置控制消息级别为套接字级别cmsg->cmsg_type = SCM_RIGHTS; // 设置控制消息类型为传递文件描述符cmsg->cmsg_len = CMSG_LEN(sizeof(int)); // 设置控制消息长度*((int *) CMSG_DATA(cmsg)) = fd_to_send; // 将待发送的文件描述符复制到控制消息的数据部分if (sendmsg(socket, &msg, 0) == -1) { // 发送消息perror("sendmsg");}
}int recv_fd(int socket) {struct msghdr msg = {0}; // 定义消息头结构体并初始化struct iovec iov[1]; // 定义数据块结构体数组struct cmsghdr *cmsg; // 定义控制消息头指针char control[CMSG_SPACE(sizeof(int))]; // 控制信息缓冲区char dummy; // 用于填充数据块的虚拟字符iov[0].iov_base = &dummy; // 设置数据块的基址为虚拟字符的地址iov[0].iov_len = 1; // 设置数据块的长度为1字节msg.msg_iov = iov; // 设置消息头的数据块数组msg.msg_iovlen = 1; // 设置数据块数组的长度msg.msg_control = control; // 设置消息头的控制信息msg.msg_controllen = sizeof(control); // 设置控制信息的长度if (recvmsg(socket, &msg, 0) == -1) { // 接收消息perror("recvmsg");return -1;}cmsg = CMSG_FIRSTHDR(&msg); // 获取第一个控制消息头unsigned char *data = CMSG_DATA(cmsg); // 获取控制消息的数据部分int fd = *((int *) data); // 提取文件描述符return fd; // 返回接收到的文件描述符
}int main() {int socket_pair[2]; // 套接字对int file_fd; // 文件的文件描述符pid_t pid;char buf[1024];// 创建套接字对if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair) == -1) {perror("socketpair");exit(EXIT_FAILURE);}// 创建子进程pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程close(socket_pair[1]); // 关闭子进程不需要的写入端// 从套接字中读取父进程传递的文件描述符int received_fd = recv_fd(socket_pair[0]);// 使用接收到的文件描述符操作文件Assize_t num_read;while ((num_read = read(received_fd, buf, sizeof(buf))) > 0) {write(STDOUT_FILENO, buf, num_read); // 在子进程中输出文件内容}if (num_read == -1) {perror("read");exit(EXIT_FAILURE);}close(received_fd); // 关闭文件描述符close(socket_pair[0]); // 关闭套接字读取端_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程close(socket_pair[0]); // 关闭父进程不需要的读取端// 在fork后打开文件并获取文件描述符file_fd = open("fileA.txt", O_RDONLY);if (file_fd == -1) {perror("open");exit(EXIT_FAILURE);}// 将文件描述符通过套接字传递给子进程send_fd(socket_pair[1], file_fd);close(file_fd); // 关闭父进程中的文件描述符close(socket_pair[1]); // 关闭套接字写入端wait(NULL); // 等待子进程结束exit(EXIT_SUCCESS); // 退出父进程}return 0;
}
相关文章:
【Linux C | 网络编程】进程间传递文件描述符socketpair、sendmsg、recvmsg详解
我们的目的是,实现进程间传递文件描述符,是指 A进程打开文件fileA,获得文件描述符为fdA,现在 A进程要通过某种方法,传递fdA,使得另一个进程B,获得一个新的文件描述符fdB,这个fdB在进程B中的作用…...
高并发内存池(六)Page Cache回收功能的实现
当Page Cache接收了一个来自Central Cache的Span,根据Span的起始页的_pageId来对前一页所对应的Span进行查找,并判断该Span,是否处于使用状态,从而看是否可以合并,如果可以合并继续向前寻找。 当该Span前的空闲Span查…...

浅析JWT原理及牛客出现过的相关面试题
原文链接:https://kixuan.github.io/posts/f568/ 对jwt总是一知半解,而且项目打算写个关于JWT登录的点,所以总结关于JWT的知识及网上面试考察过的点 参考资料: Cookie、Session、Token、JWT_通俗地讲就是验证当前用户的身份,证明-…...

Spring AI (五) Message 消息
5.Message 消息 在Spring AI提供的接口中,每条信息的角色总共分为三类: SystemMessage:系统限制信息,这种信息在对话中的权重很大,AI会优先依据SystemMessage里的内容进行回复; UserMessage:用…...
【windows Docker desktop】在git bash中报错 docker: command not found 解决办法
【windows Docker desktop】在git bash中报错 docker: command not found 解决办法 1. 首先检查在windows中环境变量是否设置成功2. 检查docker在git bash中环境变量是否配置3. 重新加载终端配置4. 最后在校验一下是否配置成功 1. 首先检查在windows中环境变量是否设置成功 启…...

02.FreeRTOS的移植
文章目录 FreeRTOS移植到STM32F103ZET6上的详细步骤1. 移植前的准备工作2. 添加FreeRTOS文件3. 修改SYSTEM文件4. 修改中断相关文件5. 修改FreeRTOSConfig.h文件6. 可选步骤 FreeRTOS移植到STM32F103ZET6上的详细步骤 1. 移植前的准备工作 **基础工程:**内存管理部…...
【个人笔记】一个例子理解工厂模式
工厂模式优点:创建时类名过长或者参数过多或者创建很麻烦等情况时用,可以减少重复代码,简化对象的创建过程,避免暴露创建逻辑,也适用于需要统一管理所有创建对象的情况,比如线程池的工厂类Executors 简单工…...

【C语言】数组栈的实现
栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈&#…...
kafka 各种选举过程
一、kafka 消费者组协调器 如何选举 Kafka 中的消费者组协调器(Group Coordinator)是通过以下步骤选举的: 分区映射: Kafka 使用一个特殊的内部主题 __consumer_offsets 来存储消费者组的元数据。该主题有多个分区,每…...

树与二叉树【数据结构】
前言 之前我们已经学习过了各种线性的数据结构,顺序表、链表、栈、队列,现在我们一起来了解一下一种非线性的结构----树 1.树的结构和概念 1.1树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一…...

简单几步,把浏览器书签转换成导航网页
废话不多说直奔主题上干货 Step 1 下载浏览器书签 1,电脑浏览器点击下载Pintree Pintree 是一个开源项目,旨在将浏览器书签导出成导航网站。通过简单的几步操作,就可以将你的书签转换成一个美观且易用的导航页面。 2. 安装 Pintree B…...

Mac安装Hoomebrew与升级Python版本
参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本,你可以使用以下命令来设置默认的Python版本: # 首先找到新安…...
代码审计:Bluecms v1.6
代码审计:Bluecms v1.6 漏洞列表如下(附Exp): 未完待续… 1、include/common.fun.php->getip()存在ip伪造漏洞 2、ad_js.php sql注入漏洞 Exp:view-source:http://127.0.0.3/bluecms/ad_js.php?ad_id12%20UNION%20SELECT1,2,3,4,5,6,database() 3、…...

谷粒商城实战笔记-59-商品服务-API-品牌管理-使用逆向工程的前后端代码
文章目录 一, 使用逆向工程生成的代码二,生成品牌管理菜单三,几个小问题 在本次的技术实践中,我们利用逆向工程的方法成功地为后台管理系统增加了品牌管理功能。这种开发方式不仅能快速地构建起功能模块,还能在一定程度…...

如何利用Jenkins自动化管理、部署数百个应用
目录 1. Jenkins 安装与部署步骤 1.1 系统要求 1.2 安装步骤 1.2.1 Windows 系统 1.2.2 CentOS 系统 1.3 初次配置 2. Gradle 详细配置方式 2.1 安装 Gradle 2.1.1 Windows 系统 2.1.2 CentOS 系统 2.2 配置 Jenkins 中的 Gradle 3. JDK 详细配置方式 3.1 安装 JD…...

Java之归并排序
归并排序 归并排序(Merge Sort)算法,使用的是分治思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的子问题来解决。小的子问题解决了,大问题也就解决了。 核心源码: mergeSort(m->n) merge(mergeSort(m-&g…...
了解ChatGPT API
要了解如何使用 ChatGPT API,可以参考几个有用的资源和教程,这些资源能帮助你快速开始使用 API 进行项目开发。下面是一些推荐的资源: OpenAI 官方文档: 访问 OpenAI 的官方网站可以找到 ChatGPT API 的详细文档。这里包括了 API …...

EasyAnimate - 阿里开源视频生成项目,国产版Sora,高质量长视频生成 本地一键整合包下载
EasyAnimate是阿里云人工智能平台PAI自主研发的DiT-based视频生成框架,它提供了完整的高清长视频生成解决方案,包括视频数据预处理、VAE训练、DiT训练、模型推理和模型评测等。在预训练模型的基础上,EasyAnimate可通过少量图片的LoRA微调来改…...

7月23日JavaSE学习笔记
异常: 程序中一些程序处理不了的特殊情况 异常类 Exception 继承自 Throwable 类(可抛出的) Throwable继承树 Error:错误/事故,Java程序无法处理,如 OOM内存溢出错误、内存泄漏...会导出程序崩溃 常见的…...

Linux——DNS服务搭建
(一)搭建nginx 1.首先布置基本环境 要求能够ping通外网,有yum源 2.安装nginx yum -y install nginx 然后查看验证 3.修改网页配置文件 修改文件,任意编写内容,然后去物理机测试 (二)创建一…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...