一、进程间的通信(IPC)-管道
管道分为无名管道(pipe),有名管道(FIFO)二种;
区别:无名管道是存在于内存的特殊文件,而有名管道是一个存在硬盘上的文件
无名管道的概念:管道是由内核管理的一个缓冲区,相当于放入内存的一个纸条。管道的一端连接一个进程的输出,这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失
无名管道特点:1、半双工(单向通信)机制,数据只能有一个进程流入下一个进程(一个写管道,一个读管道);全双工通信需要创建两个管道;
2、数据只能在具有血缘关系的进程间通信;
3、管道没有名字,缓冲区大小一定(被分配一个页面作为缓冲区),是一种特殊的文件—PIPE_BUF;
无名管道的创建与打开:定义头文件 #include
int pipe(int fd[2]); 成功返回0,数组中包含两个文件描述符,失败返回-1;
fd[0](管道读端) & fd[1](管道写端)用于描述管道的两端,读端只能读,写端只能写;可以用操作I/O文件的方式操作管道;
无名管道的读写:读端在读取数据时应该及时关闭不需要的管道的另一端(写端);写端亦如此
ps:必须再fork之前调用pipe函数创建管道,否则子进程无法继承管道的描述符
代码功能如下:主进程通过命令行向管道写入数据,子进程从标准输入里面读出该参数;将读端重定向到标准输入端
/* pipe.c文件*/
#include
#include
#include
#include
#include
#include
int main( int argc,char **argv)
{
pid_t pid;
int fd[2];
int stat_val;
if(pipe(fd))
{
printf("creat pipe failed\n");
exit(1);
}
pid = fork();
switch(pid)
{
case 0:
sleep(5);
close(fd[1]);
close(0);
dup(fd[0]);
//dup2(fd[0],0);
execve("ctrlprocess",(void *)argv,NULL);
exit(0);
case -1:
printf("fork failed\n");
exit(0);
default:
close(fd[0]);
write(fd[1],argv[1],strlen(argv[1]));
close(fd[1]);
wait(&stat_val);
break;
}
return 0;
}
可执行的代码:
/*ctrlprocess.c*/
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
printf("I am here\n");
char message[100];
int n;
while(1){
n=read(0,message,90);
printf("n= %d\n",n);
if(n>0)
{
printf("message= %s\n",message);
}
exit(0);
}
}程序执行如下:
有名管道(named pipe 或pipe)
特点:可以在非亲属关系中进行通信;以FIFO的文件形式存在文件系统中,是一个设备文件,相当于创建了一个文件,只要具有读写权限就可以访问
创建的方式二种:第一种,shell命令,mknod(mkfifo) 路径名>
第二种,系统函数:int mkfifo(const char *pathname,mode_t mode);//S_IFFO | 0666,表明文件存取权限
int mknod(const char *pathname,mode_t mode,dev_t dev);
成功返回0,失败返回-1;
注意:使用FIFO时要先使用open()函数将其打开;调用open打开有名管道的进程会阻塞,但如果以O_RDWR打开,一定不会阻塞;以O_RDONLY打开,则调用open的进程将会被阻塞直到有写方打开有名管道;以O_WRONLY打开,则调用open的进程也会被阻塞直到有读方打开有名管道;
/*writepipe.c*/
#include
#include
#include
#include
#include
#include
#define NAMEDPIPE "/home/czg/file/pipe"
int main(char argc,char *argv[])
{
int fd,n;
if(argc < 2)
printf("input data\n");
/* 非堵塞,只读的形式打开文件*/
fd = open(NAMEDPIPE,O_WRONLY );
if(fd<0)
{
perror("open failed");
}
printf("fd = %d\n",fd);
if(fd < 0)
printf("open failed\n");
n=write(fd,argv[1],3);
printf("n=%d\n",n);
close(fd);
return 0;
}
/* readpipe.c*/
#include
#include
#include
#include
#include
#include
#include
#include
#define NAMEDPIPE "/home/czg/file/pipe"
int main(int argc,char **argv)
{
int fd,n;
char buf[200];
memset(buf,0,sizeof(buf));
/* 确认管道文件是否存在,有则删除*/
if(access(NAMEDPIPE,F_OK)==0)
{
printf("into access\n");
execlp("rm","-f",NAMEDPIPE,NULL);
}
/* 创建管道,使其克读写执行*/
if(mkfifo(NAMEDPIPE,0777) != 0)
{
printf("mkfifo error\n");
}
/* 只读方式open管道时,进程被阻塞,至到有写方可打开管道,亦可加O_NONBLOCK(无堵塞)*/
fd = open(NAMEDPIPE,O_RDONLY );
printf("fd = %d\n",fd);
sleep(5);
while(1)
{
memset(buf,0,sizeof(buf));
n=read(fd,buf,2);
if(n==-1)
perror("read error");
else if(n==0)
printf("no data\n");
else
{
printf("get data:%s\nn=%d\n",buf,n);
sleep(2);
}
}
close(fd);
return 0;
}
代码结果: