|
本帖最后由 0xlavon 于 2024-5-22 12:52 编辑
在linux操作系统中,进程间通信(Inter-Process Communication, IPC)是进程之间传递数据或信号的机制。IPC在多进程编程中至关重要,适用于资源共享、数据同步、事件通知等场景。本文将介绍几种常见的Linux进程间通信方式,并给出相应的代码示例。
1. 管道(Pipes)
管道是一种最简单的进程间通信方式,主要用于父子进程之间的数据传输。
1.1 匿名管道(Unnamed Pipes)
匿名管道只能用于具有亲缘关系的进程之间,即父进程与子进程之间。
1.1.1 创建与使用
匿名管道通过`pipe()`系统调用创建:
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- int main() {
- int pipefd[2];
- char buffer[30];
- pid_t cpid;
- if (pipe(pipefd) == -1) {
- perror("pipe");
- exit(EXIT_FAILURE);
- }
- cpid = fork();
- if (cpid == -1) {
- perror("fork");
- exit(EXIT_FAILURE);
- }
- if (cpid == 0) { /* 子进程 */
- close(pipefd[1]); /* 关闭写端 */
- read(pipefd[0], buffer, sizeof(buffer));
- printf("子进程接收到的数据: %s\n", buffer);
- close(pipefd[0]);
- } else { /* 父进程 */
- close(pipefd[0]); /* 关闭读端 */
- write(pipefd[1], "Hello, child process", 21);
- close(pipefd[1]);
- }
- return 0;
- }
复制代码
1.2 命名管道(Named Pipes, FIFO)
命名管道可以用于任何两个进程之间的通信,具有路径名,与文件类似。
1.2.1 创建与使用
使用`mkfifo()`创建命名管道:
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- int main() {
- char *fifo = "/tmp/my_fifo";
- char buffer[30];
- if (mkfifo(fifo, 0666) == -1) {
- perror("mkfifo");
- exit(EXIT_FAILURE);
- }
- pid_t cpid = fork();
- if (cpid == 0) { /* 子进程 */
- int fd = open(fifo, O_RDONLY);
- read(fd, buffer, sizeof(buffer));
- printf("子进程接收到的数据: %s\n", buffer);
- close(fd);
- } else { /* 父进程 */
- int fd = open(fifo, O_WRONLY);
- write(fd, "Hello, child process", 21);
- close(fd);
- }
- return 0;
- }
复制代码
2. 消息队列(Message Queues)
消息队列允许进程以消息的形式进行通信,支持异步操作,且能够实现数据的结构化传输。
2.1 创建与使用
消息队列通过`msgget()`、`msgsnd()`、`msgrcv()`等系统调用进行操作:
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- struct msg_buffer {
- long msg_type;
- char msg_text[100];
- };
- int main() {
- key_t key;
- int msgid;
- struct msg_buffer message;
- key = ftok("progfile", 65);
- msgid = msgget(key, 0666 | IPC_CREAT);
- message.msg_type = 1;
- strcpy(message.msg_text, "Hello, message queue");
- msgsnd(msgid, &message, sizeof(message), 0);
- msgrcv(msgid, &message, sizeof(message), 1, 0);
- printf("接收到的消息: %s\n", message.msg_text);
- msgctl(msgid, IPC_RMID, NULL);
- return 0;
- }
复制代码
3. 共享内存(Shared Memory)
共享内存是最快的IPC方式,允许多个进程直接访问同一块内存区域。
3.1 创建与使用
共享内存通过`shmget()`、`shmat()`、`shmdt()`等系统调用进行操作:
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.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);
- strcpy(str, "Hello, shared memory");
- printf("写入数据: %s\n", str);
- shmdt(str);
- shmctl(shmid, IPC_RMID, NULL);
- return 0;
- }
复制代码
4. 信号量(Semaphores)
信号量主要用于进程同步,但也可以用于进程间通信。
4.1 创建与使用
信号量通过`semget()`、`semop()`、`semctl()`等系统调用进行操作:
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <stdio.h>
- #include <stdlib.h>
- union semun {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
- };
- int main() {
- key_t key = ftok("semfile", 65);
- int semid = semget(key, 1, 0666 | IPC_CREAT);
- union semun u;
- u.val = 1;
- semctl(semid, 0, SETVAL, u);
- struct sembuf sb = {0, -1, 0}; // P操作
- semop(semid, &sb, 1);
- printf("进入临界区\n");
- sleep(2); // 模拟临界区操作
- printf("退出临界区\n");
- sb.sem_op = 1; // V操作
- semop(semid, &sb, 1);
- semctl(semid, 0, IPC_RMID);
- return 0;
- }
复制代码
5. 套接字(Sockets)
套接字不仅用于网络通信,也可以用于本地进程间通信(Unix Domain Sockets)。
5.1 创建与使用
本地套接字通过`socket()`、`bind()`、`listen()`、`accept()`等系统调用进行操作:
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #define SOCKET_PATH "/tmp/socket"
- int main() {
- int server_fd, client_fd;
- struct sockaddr_un addr;
- char buffer[100];
- server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- memset(&addr, 0, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
- bind(server_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un));
- listen(server_fd, 5);
- client_fd = accept(server_fd, NULL, NULL);
- read(client_fd, buffer, sizeof(buffer));
- printf("接收到的数据: %s\n", buffer);
- close(client_fd);
- close(server_fd);
- unlink(SOCKET_PATH);
- return 0;
- }
复制代码
6. 总结
Linux提供了多种进程间通信方式,每种方式都有其适用的场景和优缺点:
(1) 管道(匿名管道和命名管道)简单易用,适用于父子进程或相关进程之间的通信。
(2) 消息队列适用于需要结构化数据传输且通信双方相对独立的场景。
(3) 共享内存是最快的通信方式,但需要进程间同步机制确保数据一致性。
(4) 信号量主要用于进程同步,也可以结合其他IPC方式使用。
(5) 套接字适用于本地和网络通信,具有很强的灵活性和扩展性。
选择合适的IPC方式,能够有效提高系统的性能和稳定性。希望本文能帮助读者更好地理解和应用Linux进程间通信技术。Happy coding with Linux IPC!
|
|