Linux进程间通信

  • Linux进程间通信已关闭评论
  • 171 次浏览
  • A+
所属分类:linux技术
摘要

具有亲缘关系的两个进程间通信,半双工通信,要实现全双工通信需要创建两个pipe。


匿名管道pipe

具有亲缘关系的两个进程间通信,半双工通信,要实现全双工通信需要创建两个pipe。

相关系统调用

函数名 作用
fork() 复制一个子进程。
pipe() 创建一个管道。
close() 用于关闭管道读/写端。
write() 向管道写入。
read() 从管道读出。

实例

#include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h>  int main() {     int result = -1;     char str[] = "hello,process!";  //要写入的数据     char buf[256];  //读出缓冲区     int fd[2];  //读/写文件描述符     int *pipe_read = &fd[0];  //管道读写指针,便于区分读写文件描述符     int *pipe_write = &fd[1];     pid_t pid = -1;   //进程号,用于标识子进程与父进程      result = pipe(fd);  //创建管道     if(result != 0) {         printf("open pipe ERRORn");         exit(0);     }     pid = fork();  //创建子进程     if(pid == -1) {         printf("create process ERRORn");         exit(0);     }     if(pid == 0) {  //子进程         close(*pipe_read);  //关闭通道读功能         write(*pipe_write, str, strlen(str));  //管道写         close(*pipe_write);  //写完关闭文件描述符     }else {         close(*pipe_write);         read(*pipe_read, buf, sizeof(buf));         close(*pipe_read);         printf("收到子进程数据:%s", buf);     }     return 0; }  

运行结果:

[Running] cd "/home/tayoou/pipe/" && gcc pipe.c -o pipe && "/home/tayoou/pipe/"pipe 收到子进程数据:hello,process! 

命名管道fifo

无亲缘关系的进程间进行通信,是一种特殊的文件,在文件系统中以文件名的形式存在,数据存储在内存中,命名管道可以在终端创建或程序中创建。

相关函数

函数名 功能
mkfifo() 创建一个命名管道。
open() 打开一个命名管道(文件)。
read() 读命名管道(文件)。
write() 写命名管道(文件)。

实例

fifo_write.c

#include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdio.h>  int main() {     int result = -1;     int fifo_fd = -1;  //命名管道文件描述符     char str[] = "hello fifo!";      result = mkfifo("myfifo", 0666);  //创建命名管道,读写权限拉满,由于命名管道不可执行,因此不是0777      if(result != 0) {         printf("create mkfifo FAILn");         exit(0);     }      fifo_fd = open("myfifo", O_WRONLY); //只写打开命名管道     //fifo_fd = open("myfifo", O_WRONLY | O_NONBLOCK); //非阻塞方式写          if(fifo_fd == -1) {         printf("open fifo FAILn");         exit(0);     }          result = write(fifo_fd, str, strlen(str));  //向命名管道写      if(result == -1) {         printf("write fifo FAILn");         exit(0);     }          printf("write %s to fifon", str);     close(fifo_fd);     return 0; } 

fifo_read.c

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h>  int main() {     int read_fd = -1;     int result = -1;     char buf[256];     read_fd = open("myfifo", O_RDONLY);  //打开命名管道,只读      if(read_fd == -1) {         printf("open fifo FAILn");         exit(0);     }          memset(buf, 0, sizeof(buf));  //数组初始化     result = read(read_fd, buf, sizeof(buf));  //从命名管道读     //fifo_fd = open("myfifo", O_WRONLY | O_NONBLOCK); //非阻塞方式读      if(result == -1) {         printf("read fifo FAILn");         exit(0);     }      printf("recive %s from fifon", buf);     close(read_fd);     return 0; } 

运行结果:

tayoou@:~/fifo$ ./fifo_write write hello fifo! to fifo tayoou@:~/fifo$ ./fifo_read recive hello fifo! from fifo 

消息队列MQ

相关函数

函数名 功能
msgget() 创建/获取消息队列
msgsnd() 发送消息到消息队列
msgrcv() 从消息队列获取消息
msgctl() 控制消息队列(包括删除)

实例

mq_send.c

#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h>  struct mq_send {     long type;  //消息类型,用来表示某一类消息     char data[256];     //消息内容 };  int main() {     int qid = -1;  //消息队列ID     struct mq_send msg;     int result = -1;     qid = msgget((key_t)1234, IPC_CREAT | 0666);  //创建消息队列,用key值来唯一标识一个消息队列,权限为0666      if(qid == -1) {         printf("creat msgget FAILn");         exit(0);     }     while(1) {         memset(msg.data, 0, sizeof(msg.data));  //初始化数组         if(fgets(msg.data, sizeof(msg.data), stdin) == NULL) {  //获取键盘输入             printf("stdin FAILn");             exit(0);         }          msg.type = getpid();  //获得进程号,此步并非必须,可以设置type为大于0的任意值         result = msgsnd(qid, &msg, sizeof(msg.data), 0);  //发送data到mq         if(result == -1) {             printf("send msg FAILn");             exit(0);         }          printf("send msg to mq: %s", msg.data);          if(strcmp(msg.data, "quitn") == 0) {  //退出判断逻辑             printf("quit SUCCESSn");             exit(0);         }     } } 

mq_rcv.c

#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h>  struct mq_rcv {     long type;     char data[256]; };  int main() {     int qid = -1;     struct mq_rcv msg;     int result = -1;     qid = msgget((key_t)1234, IPC_CREAT | 0666);  //使用相同的消息队列key值获取消息队列ID     if(qid == -1) {         printf("creat mq FAILn");         exit(0);     }      while(1) {         result = msgrcv(qid, &msg, sizeof(msg.data), 0, 0);  //从消息队列获取消息,第四个0(type)表示不按类型取,直接取mq的第一个消息。第五个0(msgflg)表示使用默认方式(阻塞)获取消息。         if(result == -1) {             printf("read mq FAILn");             exit(0);         }         printf("recive data from mq: %s", msg.data);         if(strcmp(msg.data, "quitn") == 0) {             msgctl(qid, IPC_RMID, NULL);  //删除消息队列。             printf("close mq SUCCESSn");             break;         }     }     return 0; } 

运行结果:

tayoou@:~/mq$ ./mq_send test send msg to mq: test nihao send msg to mq: nihao :) send msg to mq: :) quit send msg to mq: quit quit SUCCESS 
tayoou@:~/mq$ ./mq_rcv recive data from mq: test recive data from mq: nihao recive data from mq: :) recive data from mq: quit close mq SUCCESS 

进程信号量 system-V

本质是计数器,用于保护临界资源。不同于全局变量,信号量的P/V是原子操作。区别于线程POSIX信号量。

相关函数

函数名 功能
semget() 创建、获取信号量集
semop() 进行PV操作
semctl() 管理信号量

示例