在操作系统中,进程间通信(IPC,Inter-Process Communication)是指在独立进程之间交换数据或消息的机制。由于不同进程具有独立的地址空间,因此 IPC 机制必须依赖内核或特定工具来实现数据共享和同步。
以下是常见的 6种进程间通信方式,每种方法都有其适用场景和特点:
🔹 1. 管道 (Pipe)
➤ 原理
- 管道是一种半双工(单向)通信机制,数据只能沿一个方向流动。
- 通信的进程必须具有亲缘关系(如父子进程)。
➤ 特点
✅ 简单易用,基于文件描述符;
✅ 仅支持单向通信,数据流向固定;
✅ 适用于父子进程之间的通信;
➤ 示例代码 (C - pipe()
)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd[2];
char buffer[100];
pipe(fd); // 创建管道
if (fork() == 0) { // 子进程
close(fd[0]); // 关闭读端
write(fd[1], "Hello from child!", 18);
} else { // 父进程
close(fd[1]); // 关闭写端
read(fd[0], buffer, sizeof(buffer));
printf("父进程接收数据: %s\n", buffer);
}
return 0;
}
🔹 2. 命名管道 (Named Pipe / FIFO)
➤ 原理
- 命名管道是一种改进版的管道,支持无亲缘关系的进程通信。
- FIFO 以文件形式存在,数据通过文件路径传输。
➤ 特点
✅ 可用于任意进程;
✅ 数据具有顺序性,遵循先进先出 (FIFO);
✅ 支持持久化,FIFO 文件即使无进程使用仍存在;
➤ 示例代码 (C - mkfifo()
)
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_PATH "/tmp/my_fifo"
int main() {
mkfifo(FIFO_PATH, 0666); // 创建命名管道
if (fork() == 0) { // 子进程
int fd = open(FIFO_PATH, O_WRONLY);
write(fd, "Hello from child!", 18);
close(fd);
} else { // 父进程
char buffer[100];
int fd = open(FIFO_PATH, O_RDONLY);
read(fd, buffer, sizeof(buffer));
printf("父进程接收数据: %s\n", buffer);
close(fd);
}
return 0;
}
🔹 3. 消息队列 (Message Queue)
➤ 原理
- 消息队列是由内核维护的链表结构,用于存储消息,支持消息的优先级。
➤ 特点
✅ 数据以消息为单位,每条消息独立;
✅ 支持非亲缘进程;
✅ 消息具有持久性(即使发送进程退出,消息仍可被接收进程获取)。
➤ 示例代码 (Linux - msgsnd()
/ msgrcv()
)
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#define MSG_KEY 1234
typedef struct message {
long msg_type;
char msg_text[100];
} message;
int main() {
int msgid = msgget(MSG_KEY, 0666 | IPC_CREAT);
if (fork() == 0) { // 子进程
message msg = {1, "Hello from child!"};
msgsnd(msgid, &msg, sizeof(msg.msg_text), 0);
} else { // 父进程
message msg;
msgrcv(msgid, &msg, sizeof(msg.msg_text), 1, 0);
printf("父进程接收数据: %s\n", msg.msg_text);
msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
}
return 0;
}
🔹 4. 共享内存 (Shared Memory)
➤ 原理
- 共享内存是将一块内存映射到多个进程的地址空间中,速度最快。
- 需要借助同步机制(如信号量、互斥锁)确保数据安全。
➤ 特点
✅ 速度最快,直接访问内存;
✅ 支持大数据传输;
✅ 需借助同步机制避免数据竞争;
➤ 示例代码 (Linux - shmget()
/ shmat()
)
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_KEY 1234
int main() {
int shmid = shmget(SHM_KEY, 1024, 0666 | IPC_CREAT);
char* str = (char*) shmat(shmid, NULL, 0); // 映射到内存
if (fork() == 0) { // 子进程
strcpy(str, "Hello from child!");
} else { // 父进程
sleep(1); // 等待子进程写入
printf("父进程接收数据: %s\n", str);
shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
}
return 0;
}
🔹 5. 信号 (Signal)
➤ 原理
- 信号是异步通信机制,通常用于通知进程特定事件的发生。
- 信号无需建立连接,直接由内核触发。
➤ 特点
✅ 轻量级,系统调用简单;
✅ 适用于事件通知(如 Ctrl+C、超时提醒);
✅ 不适合大数据传输;
➤ 示例代码 (C - signal()
)
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void signalHandler(int signum) {
printf("收到信号: %d\n", signum);
}
int main() {
signal(SIGINT, signalHandler); // 捕获 Ctrl+C 信号
while (1) {
printf("等待信号...\n");
sleep(2);
}
return 0;
}
🔹 6. 套接字 (Socket)
➤ 原理
- 套接字是一种全双工的通信机制,支持本地及网络中的进程通信。
➤ 特点
✅ 适用于分布式系统和远程进程通信;
✅ 提供TCP/UDP两种传输模式;
✅ 复杂度较高,适用于复杂场景;
➤ 示例代码 (C - socket()
/ bind()
/ send()
/ recv()
)
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(server_fd, 3);
int client_fd = accept(server_fd, NULL, NULL);
send(client_fd, "Hello from server", 18, 0);
return 0;
}
📝 对比总结
通信方式 | 数据流向 | 速度 | 适用场景 |
---|---|---|---|
管道 (Pipe) | 单向 | 快速 | 父子进程间快速传输小量数据 |
命名管道 (FIFO) | 单向 | 快速 | 无关进程间的快速数据交换 |
消息队列 (Message Queue) | 双向 | 中等 | 带有优先级的消息传递 |
共享内存 (Shared Memory) | 双向 | 极快 | 大量数据传输 |
信号 (Signal) | 单向 | 快速 | 异步事件通知 |
套接字 (Socket) | 双向 | 较慢 | 网络和本地进程间通信 |