命名管道定义
上一篇博客中介绍了匿名管道的用法以及他的特点,但是它存在一定的限制,例如他只能在两个具有公共祖先的进程间进行通信例如父子进程。但是如果想要在不相关的两个进程之间进行数据交互,这可以使用命名管道。命名管道是一种特殊类型的文件
命名管道创建
命令行上创建
创建命名管道可以直接在命令行上使用mkfifo命令来创建。 创建结果如下,注意的是这里的文件类型是以p开头的。 为了测试这个管道功能,可以将Linux窗口复制一份,然后进行二者之间的通信:在一端输入数据,在另一端接收数据,运行结果如下:
程序内创建
除了上面在命令行上创建命名管道的方法,我们还可以在程序中使用相应的接口函数进程管道的创建,函数定义如下:mkfifo 使用代码如下: 这里传入的第一个参数是创建管道所在的地址,我们标识一个磁盘文件,会使用路径+文件名,这具有唯一性。第二个参数则是设置创建出来的管道的权限,类似于创建文件时对文件权限的设置,这里创建命名管道时,也会受到系统掩码约束。
这里的创建管道时候,可以自定义掩码,创建出自己需要权限的管道,使用umask函数 运行结果如下:
命名管道间通信
一旦我们有了一个命名管道,此时我们只需要让通信双方按照文件操作即可。两个进程代码分别如下:
#include"com.h"
int main()
{
umask(0);
if(mkfifo(MY_FIFO,0666)<0)
{
perror("mkfifo\n");
return 1;
}
int fd = open(MY_FIFO,O_RDONLY);
if(fd<0)
{
perror("open");
return 2;
}
while(1)
{
fflush(stdout);
char buffer[64]={0};
ssize_t s = read(fd,buffer,sizeof(buffer)-1);
if(s > 0)
{
buffer[s]=0;
if(strcmp(buffer,"show")==0)
{
if(fork()==0)
{
execl("/usr/bin/ls","ls","-l",NULL);
exit(-1);
}
waitpid(-1,NULL,0);
}
else if(strcmp(buffer,"run")==0)
{
if(fork()==0)
{
execl("/usr/bin/sl","sl",NULL);
}
}
else
{
printf("client %s\n",buffer);
}
}
else if(s==0)
{
printf("client close\n");
break;
}
else
{
perror("read\n");
break;
}
}
close(fd);
return 0;
}
#include"com.h"
int main()
{
int fd = open(MY_FIFO,O_WRONLY);
if(fd < 0)
{
perror("open");
return 1;
}
while(1)
{
printf("请输入:");
fflush(stdout);
char buffer[64]={0};
ssize_t s = read(0,buffer,sizeof(buffer)-1);
if(s > 0)
{
buffer[s-1]=0;
printf("%s\n",buffer);
write(fd,buffer,strlen(buffer));
}
}
close(fd);
return 0;
}
这里可以看的在client文件中输入相应的命令,在server中可以接收到。
匿名管道和命名管道区别
匿名管道由pipe函数创建并打开。 命名管道由mkfifo函数创建,打开用open FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。 命名管道:该管道需要有名字,为了保证不同的进程看到同一个文件,必须要有名字 匿名管道:文件没有名字,因为他是通过父子继承的方式看到同一份资源,所以不需要名字。 因为命名管道也是基于字节流的,所以实际上,信息传递的时候,是需要通信双方定制“协议的”
|