当前位置: 首页 > news >正文

【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系统中,文件描述符是进程特定的,它们不能简单地通过整数值在不同的进程之间传递。直接通过管道传递文件描述符的整数值是无效的,因为文件描述符是相对于进程的。

要正确地传递文件描述符,必须使用sendmsgrecvmsg系统调用,以及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 结构体中指定的缓冲区中。
  • 控制消息传递

    • sendmsgrecvmsg 支持通过 msg_controlmsg_controllen 参数传递控制消息(cmsghdr 结构体),特别是用于传递文件描述符等特殊信息。
  • 应用场景

    • 进程间通信(IPC):sendmsgrecvmsg 可以在进程间传递复杂的数据结构和文件描述符,适用于需要高效数据传输和资源共享的场景。
    • 网络编程:在网络编程中,这两个函数用于向套接字发送数据和从套接字接收数据,支持分散/聚集操作和控制消息传递。

作用

  • 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 数组中指定的多个缓冲区中。
  • 数据传输

    • writevreadv 函数支持数据的分散(scatter)和聚集(gather)操作,可以高效地处理多个非连续数据块的读写。
  • 应用场景

    • 在网络编程中,writevreadv 可以用于同时发送或接收多个数据块,提高数据传输的效率。
    • 在文件操作中,对于需要同时读写多个缓冲区数据的场景,如日志文件写入等,也可以使用这两个函数。

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详解

我们的目的是&#xff0c;实现进程间传递文件描述符&#xff0c;是指 A进程打开文件fileA,获得文件描述符为fdA&#xff0c;现在 A进程要通过某种方法&#xff0c;传递fdA&#xff0c;使得另一个进程B&#xff0c;获得一个新的文件描述符fdB&#xff0c;这个fdB在进程B中的作用…...

高并发内存池(六)Page Cache回收功能的实现

当Page Cache接收了一个来自Central Cache的Span&#xff0c;根据Span的起始页的_pageId来对前一页所对应的Span进行查找&#xff0c;并判断该Span&#xff0c;是否处于使用状态&#xff0c;从而看是否可以合并&#xff0c;如果可以合并继续向前寻找。 当该Span前的空闲Span查…...

浅析JWT原理及牛客出现过的相关面试题

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

Spring AI (五) Message 消息

5.Message 消息 在Spring AI提供的接口中&#xff0c;每条信息的角色总共分为三类&#xff1a; SystemMessage&#xff1a;系统限制信息&#xff0c;这种信息在对话中的权重很大&#xff0c;AI会优先依据SystemMessage里的内容进行回复&#xff1b; UserMessage&#xff1a;用…...

【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. 移植前的准备工作 **基础工程&#xff1a;**内存管理部…...

【个人笔记】一个例子理解工厂模式

工厂模式优点&#xff1a;创建时类名过长或者参数过多或者创建很麻烦等情况时用&#xff0c;可以减少重复代码&#xff0c;简化对象的创建过程&#xff0c;避免暴露创建逻辑&#xff0c;也适用于需要统一管理所有创建对象的情况&#xff0c;比如线程池的工厂类Executors 简单工…...

【C语言】数组栈的实现

栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#…...

kafka 各种选举过程

一、kafka 消费者组协调器 如何选举 Kafka 中的消费者组协调器&#xff08;Group Coordinator&#xff09;是通过以下步骤选举的&#xff1a; 分区映射&#xff1a; Kafka 使用一个特殊的内部主题 __consumer_offsets 来存储消费者组的元数据。该主题有多个分区&#xff0c;每…...

树与二叉树【数据结构】

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

简单几步,把浏览器书签转换成导航网页

废话不多说直奔主题上干货 Step 1 下载浏览器书签 1&#xff0c;电脑浏览器点击下载Pintree Pintree 是一个开源项目&#xff0c;旨在将浏览器书签导出成导航网站。通过简单的几步操作&#xff0c;就可以将你的书签转换成一个美观且易用的导航页面。 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版本&#xff0c;你可以使用以下命令来设置默认的Python版本&#xff1a; # 首先找到新安…...

代码审计:Bluecms v1.6

代码审计&#xff1a;Bluecms v1.6 漏洞列表如下(附Exp)&#xff1a; 未完待续… 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-品牌管理-使用逆向工程的前后端代码

文章目录 一&#xff0c; 使用逆向工程生成的代码二&#xff0c;生成品牌管理菜单三&#xff0c;几个小问题 在本次的技术实践中&#xff0c;我们利用逆向工程的方法成功地为后台管理系统增加了品牌管理功能。这种开发方式不仅能快速地构建起功能模块&#xff0c;还能在一定程度…...

如何利用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)算法&#xff0c;使用的是分治思想。分治&#xff0c;顾名思义&#xff0c;就是分而治之&#xff0c;将一个大问题分解成小的子问题来解决。小的子问题解决了&#xff0c;大问题也就解决了。 核心源码: mergeSort(m->n) merge(mergeSort(m-&g…...

了解ChatGPT API

要了解如何使用 ChatGPT API&#xff0c;可以参考几个有用的资源和教程&#xff0c;这些资源能帮助你快速开始使用 API 进行项目开发。下面是一些推荐的资源&#xff1a; OpenAI 官方文档&#xff1a; 访问 OpenAI 的官方网站可以找到 ChatGPT API 的详细文档。这里包括了 API …...

EasyAnimate - 阿里开源视频生成项目,国产版Sora,高质量长视频生成 本地一键整合包下载

EasyAnimate是阿里云人工智能平台PAI自主研发的DiT-based视频生成框架&#xff0c;它提供了完整的高清长视频生成解决方案&#xff0c;包括视频数据预处理、VAE训练、DiT训练、模型推理和模型评测等。在预训练模型的基础上&#xff0c;EasyAnimate可通过少量图片的LoRA微调来改…...

7月23日JavaSE学习笔记

异常&#xff1a; 程序中一些程序处理不了的特殊情况 异常类 Exception 继承自 Throwable 类&#xff08;可抛出的&#xff09; Throwable继承树 Error&#xff1a;错误/事故&#xff0c;Java程序无法处理&#xff0c;如 OOM内存溢出错误、内存泄漏...会导出程序崩溃 常见的…...

Linux——DNS服务搭建

&#xff08;一&#xff09;搭建nginx 1.首先布置基本环境 要求能够ping通外网&#xff0c;有yum源 2.安装nginx yum -y install nginx 然后查看验证 3.修改网页配置文件 修改文件&#xff0c;任意编写内容&#xff0c;然后去物理机测试 &#xff08;二&#xff09;创建一…...

C#中的wpf基础

在WPF中&#xff0c;Grid 是一种非常强大的布局控件&#xff0c;用于创建网格布局。它允许你将界面划分为行和列&#xff0c;并将控件放置在这些行和列中。 以下是一些关键点和示例&#xff0c;帮助你理解 WPF 中的 Grid&#xff1a; 基本属性 RowDefinitions&#xff1a;定义…...

基于微信小程序+SpringBoot+Vue的刷题系统(带1w+文档)

基于微信小程序SpringBootVue的刷题系统(带1w文档) 基于微信小程序SpringBootVue的刷题系统(带1w文档) 本系统是将网络技术和现代的管理理念相结合&#xff0c;根据试题信息的特点进行重新分配、整合形成动态的、分类明确的信息资源&#xff0c;实现了刷题的自动化&#xff0c;…...

SSH -i的用法

缘起 今天使用ssh -i指定私钥时遇到以下错误&#xff1a; WARNING: UNPROTECTED PRIVATE KEY FILE! Permissions 0644 for /home/ken/.ssh/my.pem are too open. It is required that your private key files are NOT accessible by others. This private key will b…...

小白学习webgis的详细路线

推荐打开boss直聘搜索相关岗位&#xff0c;查看岗位要求&#xff0c;对症下药是最快的。 第一阶段&#xff1a;基础知识准备 计算机基础 操作系统&#xff1a;理解Windows、Linux或macOS等操作系统的基本操作&#xff0c;学会使用命令行界面。网络基础&#xff1a;掌握TCP/I…...

使用ChatGPT来撰写和润色学术论文的教程(含最新升级开通ChatGpt4教程)​​

现在有了ChatGPT4o更加方便了, 但次数太少了 想要增加次数可以考虑升级开桶ChatGpt4​​ &#xff08; OPENAI4 可以减2刀&#xff09; 一、引言 在学术研究中&#xff0c;撰写高质量的论文是一项重要的技能。本教程将介绍如何利用ChatGPT来辅助完成从论文构思到润色的全过程…...

常见的 HTTP 状态码分类及说明

HTTP 响应状态码&#xff08;HTTP status code&#xff09;&#xff0c;表示服务器对请求的处理结果。常见的 HTTP 状态码有以下几类&#xff1a; 1xx: 信息响应 (Informational Responses) 100 Continue: 请求已收到&#xff0c;客户端应继续发送请求的其余部分。101 Switch…...

Leetcode700.二叉搜索树中搜索具体值

二叉搜索树的定义&#xff1a; 一颗空树或者具有以下性质的二叉树&#xff1a; 若任意节点的左子树不空&#xff0c;则左子树上所有节点的值均小于它的根节点的值&#xff1b;若任意节点的右子树不空&#xff0c;则右子树上所有节点的值均大于它的根节点的值&#xff1b;任意节…...

自动导入unplugin-auto-import+unplugin-vue-components

文章介绍 接下来将会以Vite Vue3 TS的项目来举例实现 在我们进行项目开发时&#xff0c;无论是声明响应式数据使用的ref、reactive&#xff0c;或是各种生命周期&#xff0c;又或是computed、watch、watchEffect、provide-inject。这些都需要前置引入才能使用&#xff1a; …...

Conda修改包/虚拟环境储存目录

Conda修改包/虚拟环境储存目录 关键字样例 关键字 通过conda config --show [key]可以查看某个配置的值&#xff0c;[key]留空可以查看所有配置 其中&#xff1a; envs-dirs 存放虚拟环境的储存目录pkgs_dirs 包的目录 通过conda config --add [key] [value]可以为配置添加值…...

Live555源码阅读笔记:哈希表的实现(C++)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

警务平台app

智慧公安以大数据、云计算、人工智能、物联网和移动互联网技术为支撑&#xff0c;以“打、防、管、控”为目的&#xff0c;综合研判为核心&#xff0c;共享信息数据资源&#xff0c;融合业务功能&#xff0c;构建公安智慧大数据平台&#xff0c;实现公安信息数字化、网络化和智…...

Java代理模式详解

Java代理模式详解 概念 代理模式是一种设计模式&#xff0c;为其他对象提供一种代理以控制对这个对象的访问。在某些情况下&#xff0c;一个对象不适合或者不能直接引用另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的作用。在Java中&#xff0c;代理…...

docker centos镜像 npm安装包时报错“npm ERR! code ECONNRESET”

1.采用新的镜像地址 npm config set registry https://registry.npmmirror.com2.清理缓存 npm cache clean --force3.安装yarn npm install -g yarn4. 安装模块 在node_modules 同级目录执行下面命令&#xff1a; yarn add napi-build-utils env-paths express ejs cors …...

Angular中component和directive的区别?

在Angular中&#xff0c;Component和Directive都是重要的构建块&#xff0c;用于构建和组织应用程序的UI。然而&#xff0c;它们有不同的用途和特点。以下是Component和Directive的主要区别&#xff1a; Component&#xff08;组件&#xff09; 1、定义&#xff1a;Component…...

Unity 资源 之 Pop It 3D 解压玩具与双人AI游戏 Unity 资源包分享

精彩呈现&#xff1a;Pop It 3D 解压玩具与双人AI游戏 Unity 资源包分享 一、Pop It 3D 解压玩具的魅力二、双人游戏的互动乐趣三、Unity 游戏资源包的优势四、如何获取资源包 亲爱的游戏爱好者们&#xff0c;今天为大家带来一款令人兴奋的游戏资源——Pop It 3D 解压玩具双人带…...

linux离线安装mysql8(单机版)

文章目录 一、检查服务器是否有残留mysql资源&#xff0c;有的话就全删除1.1、查询mysql已安装的相关依赖&#xff1a;1.2、查找含有MySQL的目录 二、安装2.1、上传mysql安装包到文件夹下并解压2.2、移动及重命名2.3、mysql用户2.4、配置mysql所需的my.cnf文件2.5、给my.cnf配置…...

【Python】快速创建一个简易 HTTP 服务器(http.server)

目录 官方文档安装教程用命令行创建编写代码创建 实例 官方文档 http.server 警告&#xff1a; http.server 不推荐用于生产环境。它仅仅实现了 basic security checks 的要求。 安装 Python3 内置标准模块&#xff0c;无需安装。&#xff08;在之前的 Python2 版本名称是 Si…...

随着软件开发方法的不断演进,Cobol 程序如何适应敏捷开发和持续集成/持续部署(CI/CD)的流程?

Cobol是一种古老的编程语言&#xff0c;最初设计用于商业数据处理。虽然它不是为敏捷开发和CI/CD流程而设计的&#xff0c;但仍然可以通过一些技术和方法来使其与这些现代开发流程兼容。 以下是一些方法可以帮助Cobol程序适应敏捷开发和CI/CD流程&#xff1a; 拆分和模块化&am…...

nodejs - MongoDB 学习笔记

一、简介 1、MongoDB 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 2、数据看是什么 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据的应用程序。 3、数据库的作用 主要作用是 管理数据…...

photoshop学习笔记——移动工具

移动工具&#xff0c;可以对图层进行移动&#xff0c;快捷键 V 使用的素材已经放上了&#xff0c;直接下载即可 按住ctrl 可以自动选取&#xff0c;鼠标点击哪个对象&#xff0c;自动选中哪个图层 按住 shift 校正角度&#xff08;只能沿着直线移动&#xff09; 按住 alt 拖…...

HarmonyOS 质量、测试、上架速浏

1.应用质量要求&#xff1a; 1. 应用体验质量建议: 功能数据完备 功能完备 数据完备 基础体验要求 基础约束 兼容性 稳定性 性能 功耗 安全…...

TS的访问修饰符有哪些

如果你和我一样是从强类型语言(如C、C#、Java)转过来的&#xff0c;相信你会一眼就知道是什么 public&#xff08;默认&#xff09; - 全部可访问 protected - 自己和派生类可访问 private - 只有自己可访问 废话不多说&#xff0c;上代码&#xff1a; class Person {publ…...

网络安全之扫描探测阶段攻防手段(二)

扫描探测 扫描探测阶段是攻击者对目标网络进行深入了解的关键步骤&#xff0c;同时也是防御者识别潜在威胁和加强安全防护的机会。 攻击端&#xff1a;技术原理和工具 端口扫描&#xff1a; 原理&#xff1a;攻击者使用端口扫描工具来识别目标网络中开放的端口&#xff0c;这…...

C++:泛型算法了解

什么是泛型算法 泛型算法是C标准模板库&#xff08;STL&#xff09;中的一部分&#xff0c;它们表示的是可以用于不同类型的元素和多种容器类型的一些经典算法的公共接口。这些算法之所以被称为“泛型”&#xff0c;是因为它们可以操作在多种容器类型上&#xff0c;包括但不限…...

基于bert的自动对对联系统

目录 概述 演示效果 核心逻辑 使用方式 1.裁剪数据集 根据自己的需要选择 2.用couplet数据集训练模型 模型存储在model文件夹中 3.将模型转换为ONNX格式 4.打开index.html就可以在前端使用此自动对对联系统了。 本文所涉及所有资源均在传知代码平台可获取。 概述 这个生成器利用…...

js-vue中多个按钮状态选中类似于复选框与单选框实现

1.vue中多个按钮状态选中类似于复选框 在Vue中处理多个按钮的选中状态切换&#xff0c;通常我们会利用Vue的响应式数据系统来追踪每个按钮的选中状态。 html <div id"app"> <button v-for"button in buttons" :key"button.id" :c…...

ObservableCollection新增数据前判断数据是否存在

public class MyDataModel {public int Id { get; set; }public string Name { get; set; }}public static void Main(){// 创建 ObservableCollectionObservableCollection<MyDataModel> myDataCollection new ObservableCollection<MyDataModel>{new MyDataMode…...

DBus快速入门

DBus快速入门 参考链接&#xff1a; 中文博客&#xff1a; https://www.e-learn.cn/topic/1808992 https://blog.csdn.net/u011942101/article/details/123383195 https://blog.csdn.net/weixin_44498318/article/details/115803936 https://www.e-learn.cn/topic/1808992 htt…...

SQL Server 设置端口号:详细步骤与注意事项

目录 一、了解SQL Server端口号的基础知识 1.1 默认端口号 1.2 静态端口与动态端口 二、使用SQL Server配置管理器设置端口号 2.1 打开SQL Server配置管理器 2.2 定位到SQL Server网络配置 2.3 修改TCP/IP属性 2.4 重启SQL Server服务 三、注意事项 3.1 防火墙设置 3…...

Python面试题:结合Python技术,如何使用NetworkX进行复杂网络分析

NetworkX 是一个强大的 Python 库&#xff0c;用于创建、操作和研究复杂网络的结构、动力学和功能。它提供了丰富的功能来处理图和网络数据&#xff0c;适合用于复杂网络分析。以下是使用 NetworkX 进行复杂网络分析的基本步骤&#xff1a; 安装 NetworkX&#xff1a; pip inst…...