上节我们讲了匿名管道,匿名管道是用于具有亲缘关系的进程进行通信的方式。其特点是子进程继承父进程的属性,继承了文件描述表中的信息---打开的文件。而命名管道通信方式是让磁盘上的一个文件,加载到内存,让通信的进程都能看到同一块资源。具体如下图:
?
接下来我们看一看匿名管道的创建过程,具体如下图:
?
接下来我们就要将本节重点-------命名管道
我们先看一个命令行的命名管道通信的实例:
我们创建一个管道文件 : mkfifo pipc.一个进程向pipc中写,一个从pipc中读
?
?当我们在一个进程向管道(pipc)中写入"hello other",另一个进程会收到消息
接来下我们来了解一下命名管道的原理:
首先进程是具有独立性的,进程通信的成本比较高,要实现进程通信必须需要要解决让不同进程看到同一块资源有以下几种方式
1.管道(匿名管道,命令管道(内存文件))
2.共享内存
3.消息队列
4.信号量
这些资源肯定都是操作系统提供的;pipe是通过子进程继承父进程的资源的特性,达到让不同的进程看到同一份资源,但是只适用于具有亲缘关系的进程。命名管道可以让不同进程看到同一块资源,具体如下图:
一旦我们具有了一个命令管道,此时我们只需要让通信双方按照文件操作即可!
注意:命令管道也是基于字节流的,所以实际上,信息传递的时候,是需要双方定制“协议的”,占时不考虑,我会在网络的时候讲解。今天我们就单纯的字符串通信。
1.首先我们编写server。
sever.c
#include"common.h" //定义头文件,方便不同进程拿到同一个路径+文件名
int main()
{
umask(0);
int mkid = mkfifo(PATHMANE,0666); //PATHMANE 是文件名
if( mkid < 0 )
{
perror("mkfifo()");
exit(1);
}
int fd = open(PATHMANE,O_RDONLY);
if(fd < 0)
{
perror("open()");
exit(1);
}
while(1)
{
char buf[64] = {0};
ssize_t ret = read(fd,buf,sizeof(buf));
if(ret < 0)
{
printf("read is error\n");
exit(1);
}
else if(ret > 0)
{
printf("client## %s\n",buf);
}
else
{
printf("client is qiut\n");
break;
}
}
close(fd);
}
?client.c
#include"common.h"
int main()
{
int fd = open(PATHMANE,O_WRONLY);
if(fd < 0)
{
perror("open()");
exit(1);
}
while(1)
{
printf("请输入#:");
fflush(stdout);
char buf[64] = {0};
ssize_t ret = read(0 ,buf,sizeof(buf) -1);
if(ret < 0)
{
printf("read is error\n");
exit(1);
}
else if(ret > 0)
{
buf[ret -1 ] = 0;
printf("%s\n",buf);
write(fd,buf,strlen(buf));
}
else
{
printf("client is qiut\n");
break;
}
}
close(fd);
}
common.h
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include <fcntl.h>
#include<unistd.h>
#include<sys/wait.h>
#define PATHMANE "./pipe"
#include<string.h>
#include<stdlib.h>
makefile
.PHONY:ALL
ALL: client server
client:client.c
gcc -o $@ $^
server:server.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -rf client server pipe
运行效果如下:
?当然大家也可以增加一些自己的业务逻辑比如:
#include"common.h"
int main()
{
umask(0);
int mkid = mkfifo(PATHMANE,0666);
if( mkid < 0 )
{
perror("mkfifo()");
exit(1);
}
int fd = open(PATHMANE,O_RDONLY);
if(fd < 0)
{
perror("open()");
exit(1);
}
while(1)
{
char buf[64] = {0};
ssize_t ret = read(fd,buf,sizeof(buf));
if(ret < 0)
{
printf("read is error\n");
exit(1);
}
else if(ret > 0)
{
if(strcmp(buf,"show") == 0) //client输入“show”,server执行ls- l
{
if( fork() == 0)
{
execl("/usr/bin/ls","ls","-l",NULL);
exit(1);
}
waitpid(-1,NULL,0);
}
if(strcmp(buf,"memory") == 0 )//client输入“memory”,server执行free
{
if(fork () == 0)
{
execl("/usr/bin/free","free","-m",NULL);
exit(1);
}
waitpid(-1,NULL,0);
}
printf("client## %s\n",buf);
}
else
{
printf("client is qiut\n");
break;
}
}
close(fd);
}
另外需要注意的是:命名管道是一直会在内存的,不会讲数据刷新到磁盘
我们让server休眠50秒之后在读,我们client一直在写,但是pipe管道文件一直没有变化,可以得出结论,命令管道是不会向磁盘上写入的。?
|