进程间通信的5中方式:
有名管道,匿名管道,systemv,posix消息队列,信号量,文件共享映射,
注意,5种进程间通信均操作的内核空间
首先我们来浅谈下匿名管道pipe
匿名管道是通过环形队列实现的,可实现节省空间和避免溢出等问题。
匿名管道有两个特点,一个是方向性,另一个是具有流向
匿名管道只能解决父子进程之间的通信,一般使用pipe时在fork之前进行
匿名管道一共四个文件描述符,两个读,两个写,分别指向管道的两端,而只有这四个文件描述符全部关闭,管道才可以被销毁
匿名管道的特点:1.只支持单项数据流
2.只有父子进程可通信
3.没有名字
4.管道缓冲区是有限的
5.管道所传送的是无格式字节流,这就要求读出方和写入方约定好格式,比如多少字节算一个消息。
匿名管道的API pipe(int fd[2])如果成功,则在内存中开辟内核缓冲区,并将管道的读端和写端连通
代码:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #define MSG "Test Message...." int main(void) { int fds[2]; pid_t pid; //父进程创建管道 pipe(fds); //创建子进程 pid = fork(); //确定通信方向:父写子读,关闭无用文件描述符 if(pid > 0){ close(fds[0]); printf("Parent pid:%d\n",getpid()); sleep(5); printf("parent send msg:%s\n",MSG); write(fds[1],MSG,strlen(MSG)); close(fds[1]); while(1); }else if(pid == 0){ char buf[1024]; int len; int flags; close(fds[1]); printf("Child pid:%d\n",getpid()); flags = fcntl(fds[0],F_GETFL); flags|=O_NONBLOCK; fcntl(fds[0],F_SETFL,flags);//改变管道的非阻塞属性 tryagain: len = read(fds[0],buf,sizeof(buf)); if(len == -1){ if(errno == EAGAIN){ printf("child read kernerl buf tryagain....\n"); sleep(1); goto tryagain; } } printf("Child recv msg:\n"); write(STDOUT_FILENO,buf,len); close(fds[0]); }else{ perror("fork error:"); exit(0); } return 0; }