当前位置:首页 > 技术 > 正文内容

Linux 进程间通信机制详解

访客 技术 2026年6月26日 1

在 Linux 系统中,每个进程拥有独立的虚拟地址空间,无法直接访问其他进程的内存。若要实现进程间的数据交换,必须借助内核提供的多种通信机制。

管道通信

管道是一种半双工的通信方式,数据只能单向流动。Linux 中的 | 符号就是典型的匿名管道应用:

ps auxf | grep mysql

上述命令将 ps 的输出作为 grep 的输入。匿名管道仅存在于内存中,随进程结束而销毁。

创建匿名管道需要调用 pipe() 系统函数:

int pipe_fd[2];
if (pipe(pipe_fd) == -1) {
    perror("pipe creation failed");
}
// pipe_fd[0] 为读端,pipe_fd[1] 为写端

通过 fork() 创建子进程后,父子进程可通过复制的文件描述符进行通信:

// 父进程关闭读端,子进程关闭写端
if (pid == 0) {
    close(pipe_fd[1]);  // 子进程只读
    read(pipe_fd[0], buffer, sizeof(buffer));
} else {
    close(pipe_fd[0]);  // 父进程只写
    write(pipe_fd[1], message, strlen(message));
}

命名管道(FIFO)则通过文件系统持久化:

mkfifo /tmp/my_fifo
echo "data" > /tmp/my_fifo  # 写入数据(阻塞直到被读取)
cat < /tmp/my_fifo          # 读取数据

消息队列

消息队列克服了管道无结构数据流的限制,允许按消息单元传递具有特定类型的数据:

#include <sys/msg.h>

struct msg_buffer {
    long msg_type;
    char msg_text[100];
};

// 发送消息
struct msg_buffer message;
message.msg_type = 1;
strcpy(message.msg_text, "Hello Queue");
 msgsnd(queue_id, &message, sizeof(message.msg_text), 0);

// 接收消息
msgrcv(queue_id, &message, sizeof(message.msg_text), 1, 0);
printf("Received: %s\n", message.msg_text);

消息队列存储于内核中,支持跨进程持久化通信,但存在大小限制(由 MSGMAXMSGMNB 控制)。

共享内存

共享内存提供最高效率的通信方式,多个进程映射同一物理内存区域:

#include <sys/shm.h>

// 创建共享内存段
int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);

// 映射到进程地址空间
char *shared_memory = (char*) shmat(shmid, NULL, 0);

// 使用示例
strcpy(shared_memory, "Shared data");

// 解除映射
shmdt(shared_memory);

信号量同步

为避免多个进程同时访问共享资源导致冲突,引入信号量机制:

#include <sys/sem.h>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

// 初始化信号量
union semun arg;
arg.val = 1;
semctl(sem_id, 0, SETVAL, arg);

// P操作(等待资源)
struct sembuf p_op = {0, -1, SEM_UNDO};
semop(sem_id, &p_op, 1);

// V操作(释放资源)
struct sembuf v_op = {0, 1, SEM_UNDO};
semop(sem_id, &v_op, 1);

信号通知

信号用于处理异步事件,如用户中断或系统异常:

#include <signal.h>

void signal_handler(int sig) {
    printf("Received signal %d\n", sig);
}

int main() {
    signal(SIGINT, signal_handler);  // 注册Ctrl+C处理函数
    
    while(1) {
        pause();  // 等待信号
    }
    return 0;
}

套接字通信

Socket 支持本地和网络环境下的进程通信。TCP 流式套接字示例:

// 服务端
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 3);
int client_fd = accept(server_fd, NULL, NULL);

// 客户端
int sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr *)&address, sizeof(address));
send(sock, "Hello", 5, 0);

UDP 数据报套接字无需连接:

// 发送端
sendto(sock, "data", 4, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));

// 接收端
recvfrom(sock, buffer, 100, 0, (struct sockaddr*)&src_addr, &addr_len);

本地套接字适用于同一主机进程通信:

struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/socket");

bind(sock, (struct sockaddr*)&addr, sizeof(addr));

这些通信机制各有特点:管道适合简单的单向数据流;消息队列支持结构化数据传输;共享内存提供最快的访问速度但需额外同步;信号量确保资源共享的安全性;信号处理异步事件;套接字则构建起分布式系统的基础。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。