linux进程间通信--管道通信
管道进程间通信
(1)无名管道
特点:
只能用于具有亲缘关系进程间通信(具有亲缘关系的进程具有数据拷贝动作(复制父进程创建子进程))或者兄弟进程之间
是一种单工的通信模式,具有固定的读端和写端
int pipe(int pipefd[2]);
功能:创建一个无名管道
参数:
@pipefd 获取操作无名管道的文件描述符 pipefd[0]:读无名管道 pipefd[1]:写无名管道
返回值:
成功返回0,失败返回-1
示例如下:
void write_pipe(int fd)
{
int ret;
char buf[1024];
while(1)
{
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf) - 1] = '\0';
ret = write(fd,buf,strlen(buf));
printf("write %d bytes!\n",ret);
if(strcmp(buf,"quit") == 0){
break;
}
}
return;
}
void read_pipe(int fd)
{
int ret;
char buf[1024];
while(1)
{
printf("read ....!\n");
ret = read(fd,buf,sizeof(buf));
buf[ret] = '\0';
printf("Read %d bytes : %s\n",ret,buf);
if(strcmp(buf,"quit") == 0){
break;
}
}
return;
}
int main(int argc, const char *argv[])
{
int ret;
pid_t pid;
int pipefd[2];
ret = pipe(pipefd);
if(ret < 0){
perror("Fail to pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if(pid < 0){
perror("Fail to fork");
exit(EXIT_FAILURE);
}
if(pid == 0){
close(pipefd[1]);
read_pipe(pipefd[0]);
}
if(pid > 0){
close(pipefd[0]);
write_pipe(pipefd[1]);
}
return 0;
}
功能:让父进程从键盘读入数据,然后写到无名管道,让子进程从无名管道中读取数据,然后输出,
如果输入"quit",则两个进程结束,功能比较简单
(2)管道读写规则
读端存在 ,写管道 ---->只要管道没有满,都可以写入数据到管道
读端不存在,写管道 ---->此时写管道没有意义,操作系统会发送SIGPIPE杀死写管道的进程
写端存在, 读管道 ---->此时管道中读取数据,管道中没有数据,读阻塞
写端不存在,读管道 ---->此时管道中读取数据,管道中没有数据,此时不阻塞,立即返回,返回值0
(3)有名管道
特点:
可以用于任意进程间通信,它是一种特殊的文件,在文件系统存在名字,
而文件中存放的数据是在内核空间,而不是在磁盘上
1.创建一个有名管道文件
int mkfifo(const char *pathname, mode_t mode);
@pathname 有名管道存在的路径
@mode 有名管道的权限
返回值:
成功返回0,失败返回-1
与FIFO相关的错误信息(主要如下)
EEXIST:参数filename所指定的文件已存在
EACCESS::参数filename所指定的目录无可执行权限
常用的用法:
if(access(FIFO,F_OK)==-1)
{
if(mkfifo(FIFO,0666)<0)&&(errno!=EEXIST)
{
printf("cannot create fifo file\n");
exit(1);
}
}
2.打开有名管道文件
open
如果有名管道的一端以只读的方式打开,会阻塞,直到另一端以写(只写或读写)的方式打开
如果有名管道的一端以只写的方式打开,会阻塞,直到另一端以读(只读或读写)的方式打开
3.读写操作
read /write
4.关闭管道文件
close(fd);
示例如下:
a_fifo.c:
void read_fifo(int fd)
{
int ret;
char buf[1024];
while(1)
{
printf("read ....!\n");
ret = read(fd,buf,sizeof(buf));
buf[ret] = '\0';
printf("Read %d bytes : %s\n",ret,buf);
if(strcmp(buf,"quit") == 0){
break;
}
}
return;
}
int main(int argc, const char *argv[])
{
int ret;
int fd;
if(argc < 2){
fprintf(stderr,"Usage : %s <fifo>!\n",argv[0]);
return -1;
}
ret = mkfifo(argv[1],0666);
if(ret < 0 && errno != EEXIST){
fprintf(stderr,"Fail to mkfifo %s : %s!\n",argv[1],strerror(errno));
return -1;
}
fd = open(argv[1],O_RDONLY);
if(fd < 0){
fprintf(stderr,"Fail to open %s : %s!\n",argv[1],strerror(errno));
return -1;
}
printf("open success, fd : %d!\n",fd);
read_fifo(fd);
close(fd);
return 0;
}
b_fifi.c:
void write_fifo(int fd)
{
int ret;
char buf[1024];
while(1)
{
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf) - 1] = '\0';
ret = write(fd,buf,strlen(buf));
printf("write %d bytes!\n",ret);
if(strcmp(buf,"quit") == 0){
break;
}
}
return;
}
//./a.out fifo
int main(int argc, const char *argv[])
{
int ret;
int fd;
if(argc < 2){
fprintf(stderr,"Usage : %s <fifo>!\n",argv[0]);
return -1;
}
ret = mkfifo(argv[1],0666);
if(ret < 0 && errno != EEXIST){
fprintf(stderr,"Fail to mkfifo %s : %s!\n",argv[1],strerror(errno));
return -1;
}
fd = open(argv[1],O_WRONLY);
if(fd < 0){
fprintf(stderr,"Fail to open %s : %s!\n",argv[1],strerror(errno));
return -1;
}
printf("open success, fd : %d!\n",fd);
write_fifo(fd);
close(fd);
return 0;
}
功能如下:
A进程向有名管道中写数据 , B进程从有名管道中读取数据 (A,B进程没有亲缘关系)
编译a_fifi.c 和b_fifi.c
gcc a_fifio.c -o a
gcc b_fifio.c -o b
并运行
a fifo
b fifo
管道通信还是比较简单!