由于现代操作系统中,进程间都是地址空间隔离的,每一个进程都有独立的地址空间,而我们的业务软件为了良好的架构和运维都会进行模块化设计,IPC进程间通信是一个必须要掌握的技能。进程间通信(IPC)是指在不同进程之间传递数据或信号的一系列方法。进程间通信有很多种方式,每种方式都会有自己的特点。
在Linux系统中,IPC包括多种机制,主要有管道(Pipes)、信号(Signals)、消息队列(Message Queues)、共享内存(Shared Memory)和信号量(Semaphores)、套接字(socket)、内存映射等,今天先介绍前四种。
1. 管道(Pipes)
管道是最简单的IPC形式。我们可以把它想象成一个数据流水线,一个进程在管道的一端放入数据,另一个进程从另一端取出数据。管道分为匿名管道和命名管道。
-
匿名管道是临时的,通常用于父子进程间的通信。
#include <stdio.h>
#include <unistd.h>
int main() {
int pipefd[2];
pid_t cpid;
char buf;
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
cpid = fork();
if (cpid == -1) {
perror("fork");
return 1;
}
if (cpid == 0) { // 子进程
close(pipefd[1]); // 关闭写端
while (read(pipefd[0], &buf, 1) > 0) {
write(STDOUT_FILENO, &buf, 1);
}
write(STDOUT_FILENO, "n", 1);
close(pipefd[0]);
_exit(0);
} else { // 父进程
close(pipefd[0]); // 关闭读端
write(pipefd[1], "Hello, World!", 13);
close(pipefd[1]);
wait(NULL);
return 0;
}
}
-
命名管道(FIFO)是一种特殊文件类型,在文件系统中有对应的文件名。可以用于不相关进程间的通信。
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
int fd;
char *myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666); // 创建命名管道
char arr1[80], arr2[80];
// 写入数据
fd = open(myfifo, O_WRONLY);
fgets(arr2, 80, stdin);
write(fd, arr2, sizeof(arr2));
close(fd);
// 读取数据
fd = open(myfifo, O_RDONLY);
read(fd, arr1, sizeof(arr1));
printf("User2: %sn", arr1);
close(fd);
return 0;
}
信号是一种较为简单的通信方式,用于通知接收进程某个事件已经发生。以下是一个捕获SIGINT
(通常由Ctrl+C
产生)的例子:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigint_handler(int sig) {
write(1, "Caught SIGINT!n", 15);
}
int main() {
signal(SIGINT, sigint_handler);
while (1) {
sleep(1);
}
return 0;
}
3. 消息队列(Message Queues)
消息队列允许一个或多个进程向它写入消息,然后由另一个进程读取。这些消息存储在内核中,并按照顺序发送。
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg {
long msg_type;
char msg_text[100];
};
int main() {
key_t key = ftok("ipcfile", 65); // 创建唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列
struct my_msg message;
message.msg_type = 1;
printf("Write Data : ");
fgets(message.msg_text, sizeof(message.msg_text), stdin);
msgsnd(msgid, &message, sizeof(message), 0); // 发送消息
printf("Data send is : %s n", message.msg_text);
return 0;
}
4. 共享内存(Shared Memory)
共享内存是最快的IPC方式,因为进程是直接对内存进行访问。但是,由于多个进程可以同时访问,因此需要使用信号量进行同步。
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main() {
key_t key = ftok("shmfile",65);
int shmid = shmget(key,1024,0666|IPC_CREAT);
char *str = (char*) shmat(shmid,(void*)0,0);
printf("Write Data : ");
gets(str);
printf("Data written in memory: %sn",str);
shmdt(str);
return 0;
}
在实际应用中,选择哪种IPC机制取决于具体需求,如数据的大小、传输速度、同步与异步等。每种机制都有其适用场景和优缺点。在设计系统时,需要根据实际场景和需求进行合理选择。
推荐一本开发者必备的经典手册,Linux编程资深专家Michael Kerrisk在书中详细描述了Linux/UNIX系统编程所涉及的系统调用和库函数,并辅之以全面而清晰的代码示例。《Linux/UNIX系统编程手册(上、下册)》涵盖了逾500个系统调用及库函数,并给出逾200个程序示例,另含88张表格和115幅示意图。
公众号后台回复“linux编程手册”获取下载链接

点个在看你最好看

原文始发于微信公众号(计算机刨根问底):轻松掌握IPC技巧,读懂Linux进程间通信(一)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/207781.html