进程通信--匿名管道和命名管道
Posted 你快看看我
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程通信--匿名管道和命名管道相关的知识,希望对你有一定的参考价值。
通信的本质是传递数据,是相互的。进程之间不能“直接”相互传递数据,因为进程具有独立性,所有的数据操作都会发生写时拷贝,所以一定要通过媒介的方式来传播。
什么是管道?管道是Unix最古老的进程间通信的形式,我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。
一.匿名管道
供具有血缘关系的进程进行进程间通信,常见于父子进程。
1.父进程创建管道
以读方式打开一次,以写方式打开一次,文件描述符3,4就会指向同一个文件
2.父进程fork出子进程
子进程写时拷贝父进程
3.父进程关闭fd[0],子进程关闭fd[1]
父子进程各自关闭不需要的文件描述符,来达到构建单向通信的信道目的,父进程写入,子进程读取
为什么曾经读写端都要打开?因为不打开rw,子进程拿到的文件打开方式必定和父进程一样,两个都是r或者两个都是w,无法通信;父进程w子进程r或者子进程w父进程r更加灵活。
为什么一定要关闭呢?因为放置误操作。
管道为什么只能单向通信呢?因为读写位只有一个。
例子:从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( void )
int fds[2];
char buf[100];
int len;
if ( pipe(fds) == -1 )
perror("make pipe"),exit(1);
// read from stdin
while ( fgets(buf, 100, stdin) )
len = strlen(buf);
// write into pipe
if ( write(fds[1], buf, len) != len )
perror("write to pipe");
break;
memset(buf, 0x00, sizeof(buf));
// read from pipe
if ( (len=read(fds[0], buf, 100)) == -1 )
perror("read from pipe");
break;
// write to stdout
if ( write(1, buf, len) != len )
perror("write to stdout");
break;
二.匿名管道的特性
如果管道里面没有消息,父进程(读端)就会等待,等子进程写入,管道内部有数据就绪;如果管道里面写端已经写满了,不能继续写了,等待父进程读取,管道内部有空闲空间;如果读端在读,但是写端不写并且关闭,读端读取到0,文件结束;如果读端不读,而且读端关闭,一直写毫无意义,一直写本质就是在浪费系统资源,写进程会立马被OS终止掉,此时写进是子进程,通过发送信号的方式
(1)管道自带同步机制
(2)管道是单向通信的
(3)管道是面向字节流的
(4)管道只能保证是具有血缘关系的进程通信,常用于父子
(5)管道可以保证一定程度的数据读取的原子性
(6)进程退出,曾经打开的文件也会被关掉,管道也是文件,管道的声明周期是随进程的
三.命名管道
管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:$ mkfifo filename
命名管道也可以从程序里创建,相关函数有:int mkfifo(const char *filename,mode_t mode);
创建命名管道:
int main(int argc, char *argv[])
mkfifo("p2", 0644);
return 0;
匿名管道和命名管道的区别:
(1)匿名管道由pipe函数创建并打开。
(2)命名管道由mkfifo函数创建,打开用open
(3)FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。
四.用命名管道实现server&client通信
# ll
total 12
-rw-r--r--. 1 root root 46 Sep 18 22:37 clientPipe.c
-rw-r--r--. 1 root root 164 Sep 18 22:37 Makefile
-rw-r--r--. 1 root root 46 Sep 18 22:38 serverPipe.c
# cat Makefile
.PHONY:all
all:clientPipe serverPipe
serverPipe.c
clientPipe:clientPipe.c
gcc -o $@ $^
serverPipe:serverPipe.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f clientPipe serverPipe
serverPipe.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define ERR_EXIT(m) \\
do\\
perror(m);\\
exit(EXIT_FAILURE);\\
while(0)
int main()
umask(0);
if(mkfifo("mypipe", 0644) < 0)
ERR_EXIT("mkfifo");
int rfd = open("mypipe", O_RDONLY);
if(rfd < 0)
ERR_EXIT("open");
char buf[1024];
while(1)
buf[0] = 0;
printf("Please wait...\\n");
ssize_t s = read(rfd, buf, sizeof(buf)-1);
if(s > 0 )
buf[s-1] = 0;
printf("client say# %s\\n", buf);
else if(s == 0)
printf("client quit, exit now!\\n");
exit(EXIT_SUCCESS);
else
ERR_EXIT("read");
close(rfd);
return 0;
clientPipe.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define ERR_EXIT(m) \\
do\\
perror(m);\\
exit(EXIT_FAILURE);\\
while(0)
int main()
int wfd = open("mypipe", O_WRONLY);
if(wfd < 0)
ERR_EXIT("open");
char buf[1024];
while(1)
buf[0] = 0;
printf("Please Enter# ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf)-1);
if(s > 0 )
buf[s] = 0;
write(wfd, buf, strlen(buf));
else if(s <= 0)
ERR_EXIT("read");
close(wfd);
return 0;
以上是关于进程通信--匿名管道和命名管道的主要内容,如果未能解决你的问题,请参考以下文章