一、进程通信基础概念
1.1 进程隔离原理
现代操作系统通过虚拟内存技术为每个进程创建独立的地址空间,这种隔离机制保障了系统的安全性,但也导致进程无法直接访问彼此的内存数据。进程间通信(IPC)正是为解决这一矛盾而设计的核心机制。
1.2 IPC分类体系
主要通信方式可分为:
传统Unix IPC:管道、FIFO
System V IPC:消息队列、信号量、共享内存
POSIX IPC:改进的消息队列、信号量、共享内存
网络扩展:套接字(本地/网络)
高级封装:D-Bus、RPC等
二、核心通信机制详解
2.1 匿名管道(Anonymous Pipes)
实现原理:
使用单向数据通道,通过pipe()系统调用创建,返回两个文件描述符(fd[0]读端,fd[1]写端)
#include <unistd.h> #include <stdio.h> #define BUFFER_SIZE 25 int main() { int fd[2]; pid_t pid; char buffer[BUFFER_SIZE]; if (pipe(fd) == -1) { perror("pipe creation failed"); exit(EXIT_FAILURE); } pid = fork(); if (pid == 0) { // 子进程 close(fd[1]); // 关闭写端 read(fd[0], buffer, BUFFER_SIZE); printf("Child received: %s\n", buffer); close(fd[0]); } else { // 父进程 close(fd[0]); // 关闭读端 const char* msg = "Hello from parent"; write(fd[1], msg, strlen(msg)+1); close(fd[1]); wait(NULL); } return 0; }
2.2 命名管道(FIFO)
创建与使用:
bash
复制
mkfifo /tmp/myfifo # 命令行创建
写入端代码:
#include <fcntl.h> #include <sys/stat.h> int main() { int fd = open("/tmp/myfifo", O_WRONLY); char* data = "FIFO Message"; write(fd, data, strlen(data)+1); close(fd); return 0; }
读取端代码:
#include <fcntl.h> int main() { int fd = open("/tmp/myfifo", O_RDONLY); char buffer[100]; read(fd, buffer, sizeof(buffer)); printf("Received: %s\n", buffer); close(fd); return 0; }
2.3 System V消息队列
完整示例:
#include <sys/ipc.h> #include <sys/msg.h> struct msg_buffer { long msg_type; char msg_text[100]; }; int main() { key_t key = ftok("progfile", 65); int msgid = msgget(key, 0666 | IPC_CREAT); // 发送消息 struct msg_buffer message = {1, "Message Content"}; msgsnd(msgid, &message, sizeof(message), 0); // 接收消息 msgrcv(msgid, &message, sizeof(message), 1, 0); printf("Received: %s\n", message.msg_text); msgctl(msgid, IPC_RMID, NULL); // 清理队列 return 0; }
2.4 共享内存进阶
带同步的共享内存示例:
#include <sys/shm.h> #include <sys/sem.h> union semun { int val; struct semid_ds *buf; unsigned short *array; }; int main() { key_t key = ftok("shmfile",65); int shmid = shmget(key, 1024, 0666|IPC_CREAT); char *str = (char*) shmat(shmid,(void*)0,0); // 创建信号量 int semid = semget(key, 1, 0666|IPC_CREAT); union semun arg; arg.val = 1; // 二进制信号量 semctl(semid, 0, SETVAL, arg); struct sembuf sb = {0, -1, 0}; // P操作 semop(semid, &sb, 1); // 临界区操作 sprintf(str, "Shared Memory Data"); printf("Data written: %s\n", str); sb.sem_op = 1; // V操作 semop(semid, &sb, 1); shmdt(str); shmctl(shmid, IPC_RMID, NULL); semctl(semid, 0, IPC_RMID); return 0; }
2.5 POSIX信号量
生产者-消费者模型示例:
#include <semaphore.h> #include <fcntl.h> #define SHM_SIZE 1024 int main() { sem_t *empty = sem_open("/empty", O_CREAT, 0644, 5); sem_t *full = sem_open("/full", O_CREAT, 0644, 0); sem_t *mutex = sem_open("/mutex", O_CREAT, 0644, 1); int shm_fd = shm_open("/buffer", O_CREAT|O_RDWR, 0666); ftruncate(shm_fd, SHM_SIZE); char *buffer = mmap(0, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0); // 生产者逻辑 for(int i=0; i<10; i++) { sem_wait(empty); sem_wait(mutex); // 写入共享内存 sprintf(buffer, "Item %d", i); sem_post(mutex); sem_post(full); } sem_close(empty); sem_unlink("/empty"); // 类似清理其他信号量和共享内存 return 0; }
三、高级通信技术
3.1 域套接字(Unix Domain Socket)
服务端实现:
#include <sys/socket.h> #include <sys/un.h> #define SOCK_PATH "/tmp/example.sock" int main() { int server_fd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path)-1); bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)); listen(server_fd, 5); int client_fd = accept(server_fd, NULL, NULL); char buffer[100]; read(client_fd, buffer, sizeof(buffer)); printf("Received: %s\n", buffer); close(client_fd); unlink(SOCK_PATH); return 0; }
3.2 内存映射文件(mmap)
跨进程文件映射示例:
#include <sys/mman.h> int main() { int fd = open("data.bin", O_RDWR | O_CREAT, 0666); ftruncate(fd, 4096); char *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); // 写入数据 sprintf(mem, "Memory mapped data"); // 同步到磁盘 msync(mem, 4096, MS_SYNC); munmap(mem, 4096); close(fd); return 0; }