linux进程间通信实战,LINUX_C编程实战-第十章《进程间通信》-管道

一、进程间的通信(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);

}

}程序执行如下:

0818b9ca8b590ca3270a3433284dd417.png

有名管道(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;

}

代码结果:

0818b9ca8b590ca3270a3433284dd417.png

你可能感兴趣的:(linux进程间通信实战)