找回密码
 立即注册
查看: 1281|回复: 0

[linux] Linux进程间通信

[复制链接]

36

主题

1

回帖

177

积分

注册会员

积分
177
发表于 2024-5-22 12:48:21 | 显示全部楼层 |阅读模式
本帖最后由 0xlavon 于 2024-5-22 12:52 编辑

linux操作系统中,进程间通信(Inter-Process Communication, IPC)是进程之间传递数据或信号的机制。IPC在多进程编程中至关重要,适用于资源共享、数据同步、事件通知等场景。本文将介绍几种常见的Linux进程间通信方式,并给出相应的代码示例。

1. 管道(Pipes)

管道是一种最简单的进程间通信方式,主要用于父子进程之间的数据传输。

1.1 匿名管道(Unnamed Pipes)

匿名管道只能用于具有亲缘关系的进程之间,即父进程与子进程之间。

1.1.1 创建与使用

匿名管道通过`pipe()`系统调用创建:


  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. int main() {
  5.     int pipefd[2];
  6.     char buffer[30];
  7.     pid_t cpid;

  8.     if (pipe(pipefd) == -1) {
  9.         perror("pipe");
  10.         exit(EXIT_FAILURE);
  11.     }

  12.     cpid = fork();
  13.     if (cpid == -1) {
  14.         perror("fork");
  15.         exit(EXIT_FAILURE);
  16.     }

  17.     if (cpid == 0) {                /* 子进程 */
  18.         close(pipefd[1]);          /* 关闭写端 */
  19.         read(pipefd[0], buffer, sizeof(buffer));
  20.         printf("子进程接收到的数据: %s\n", buffer);
  21.         close(pipefd[0]);
  22.     } else {                     /* 父进程 */
  23.         close(pipefd[0]);          /* 关闭读端 */
  24.         write(pipefd[1], "Hello, child process", 21);
  25.         close(pipefd[1]);
  26.     }

  27.     return 0;
  28. }
复制代码



1.2 命名管道(Named Pipes, FIFO)

命名管道可以用于任何两个进程之间的通信,具有路径名,与文件类似。

1.2.1 创建与使用

使用`mkfifo()`创建命名管道:


  1. #include <fcntl.h>
  2. #include <sys/stat.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>

  6. int main() {
  7.     char *fifo = "/tmp/my_fifo";
  8.     char buffer[30];

  9.     if (mkfifo(fifo, 0666) == -1) {
  10.         perror("mkfifo");
  11.         exit(EXIT_FAILURE);
  12.     }

  13.     pid_t cpid = fork();
  14.     if (cpid == 0) {    /* 子进程 */
  15.         int fd = open(fifo, O_RDONLY);
  16.         read(fd, buffer, sizeof(buffer));
  17.         printf("子进程接收到的数据: %s\n", buffer);
  18.         close(fd);
  19.     } else {            /* 父进程 */
  20.         int fd = open(fifo, O_WRONLY);
  21.         write(fd, "Hello, child process", 21);
  22.         close(fd);
  23.     }

  24.     return 0;
  25. }
复制代码




2. 消息队列(Message Queues)

消息队列允许进程以消息的形式进行通信,支持异步操作,且能够实现数据的结构化传输。

2.1 创建与使用

消息队列通过`msgget()`、`msgsnd()`、`msgrcv()`等系统调用进行操作:


  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/msg.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>

  7. struct msg_buffer {
  8.     long msg_type;
  9.     char msg_text[100];
  10. };

  11. int main() {
  12.     key_t key;
  13.     int msgid;
  14.     struct msg_buffer message;

  15.     key = ftok("progfile", 65);
  16.     msgid = msgget(key, 0666 | IPC_CREAT);
  17.     message.msg_type = 1;

  18.     strcpy(message.msg_text, "Hello, message queue");
  19.     msgsnd(msgid, &message, sizeof(message), 0);

  20.     msgrcv(msgid, &message, sizeof(message), 1, 0);
  21.     printf("接收到的消息: %s\n", message.msg_text);

  22.     msgctl(msgid, IPC_RMID, NULL);

  23.     return 0;
  24. }
复制代码



3. 共享内存(Shared Memory)

共享内存是最快的IPC方式,允许多个进程直接访问同一块内存区域。

3.1 创建与使用

共享内存通过`shmget()`、`shmat()`、`shmdt()`等系统调用进行操作:


  1. #include <sys/ipc.h>
  2. #include <sys/shm.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>

  6. int main() {
  7.     key_t key = ftok("shmfile", 65);
  8.     int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
  9.     char *str = (char*) shmat(shmid, (void*)0, 0);

  10.     strcpy(str, "Hello, shared memory");
  11.     printf("写入数据: %s\n", str);

  12.     shmdt(str);
  13.     shmctl(shmid, IPC_RMID, NULL);

  14.     return 0;
  15. }
复制代码




4. 信号量(Semaphores)

信号量主要用于进程同步,但也可以用于进程间通信。

4.1 创建与使用

信号量通过`semget()`、`semop()`、`semctl()`等系统调用进行操作:


  1. #include <sys/ipc.h>
  2. #include <sys/sem.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>

  5. union semun {
  6.     int val;
  7.     struct semid_ds *buf;
  8.     unsigned short  *array;
  9. };

  10. int main() {
  11.     key_t key = ftok("semfile", 65);
  12.     int semid = semget(key, 1, 0666 | IPC_CREAT);
  13.     union semun u;
  14.     u.val = 1;
  15.     semctl(semid, 0, SETVAL, u);

  16.     struct sembuf sb = {0, -1, 0};  // P操作
  17.     semop(semid, &sb, 1);

  18.     printf("进入临界区\n");
  19.     sleep(2);  // 模拟临界区操作
  20.     printf("退出临界区\n");

  21.     sb.sem_op = 1;  // V操作
  22.     semop(semid, &sb, 1);

  23.     semctl(semid, 0, IPC_RMID);

  24.     return 0;
  25. }
复制代码



5. 套接字(Sockets)

套接字不仅用于网络通信,也可以用于本地进程间通信(Unix Domain Sockets)。

5.1 创建与使用

本地套接字通过`socket()`、`bind()`、`listen()`、`accept()`等系统调用进行操作:


  1. #include <sys/socket.h>
  2. #include <sys/un.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>

  6. #define SOCKET_PATH "/tmp/socket"

  7. int main() {
  8.     int server_fd, client_fd;
  9.     struct sockaddr_un addr;
  10.     char buffer[100];
  11.     server_fd = socket(AF_UNIX, SOCK_STREAM, 0);

  12.     memset(&addr, 0, sizeof(struct sockaddr_un));
  13.     addr.sun_family = AF_UNIX;
  14.     strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
  15.     bind(server_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un));
  16.     listen(server_fd, 5);

  17.     client_fd = accept(server_fd, NULL, NULL);
  18.     read(client_fd, buffer, sizeof(buffer));
  19.     printf("接收到的数据: %s\n", buffer);

  20.     close(client_fd);
  21.     close(server_fd);
  22.     unlink(SOCKET_PATH);

  23.     return 0;
  24. }
复制代码




6. 总结

Linux提供了多种进程间通信方式,每种方式都有其适用的场景和优缺点:

(1) 管道(匿名管道和命名管道)简单易用,适用于父子进程或相关进程之间的通信。

(2) 消息队列适用于需要结构化数据传输且通信双方相对独立的场景。

(3) 共享内存是最快的通信方式,但需要进程间同步机制确保数据一致性。

(4) 信号量主要用于进程同步,也可以结合其他IPC方式使用。

(5) 套接字适用于本地和网络通信,具有很强的灵活性和扩展性。

选择合适的IPC方式,能够有效提高系统的性能和稳定性。希望本文能帮助读者更好地理解和应用Linux进程间通信技术。Happy coding with Linux IPC!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

联系站长|Archiver|手机版|小黑屋|主机论坛

GMT+8, 2025-4-5 02:23 , Processed in 0.064464 second(s), 24 queries .

Powered by 主机论坛 HostSsss.Com

HostSsss.Com

快速回复 返回顶部 返回列表