管道(pipe、mkfifo)
来源:互联网 发布:华为手机修改mac地址 编辑:程序博客网 时间:2024/05/16 17:19
管道概念
Linux下一切皆文件,我们可以创建一个管道文件进行通信,实际上是调用pipe函数在内核中开辟一块缓冲区(称为管道)用于通信,使不同的进程看到同一份资源,管道是一种最基本的IPC机制,由pipe函数创建 。下面我们将看到两种管道-匿名管道及命名管道的实现
匿名管道通信的实现
它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调⽤用成功返回0,调⽤用失败返回-1。
#include <unistd.h> int pipe(int file_descriptor[2]);
我们可以看到pipe函数的定义非常特别,该函数在数组中墙上两个新的文件描述符后返回0,如果返回返回-1,并设置errno来说明失败原因。
数组中的两个文件描述符以一种特殊的方式连接起来,数据基于先进先出的原则,写到_pipe[1]的所有数据都可以从_pipe[0]读回来。由于数据基于先进先出的原则,所以读取的数据和写入的数据是一致的。
特别提醒:
- pipe是基于文件描述符工作的,所以在使用pipe后,数据必须要用底层的read和write调用来读取和发送。
- 不要用_pipe[0]写数据,也不要用_pipe[1]读数据,其行为未定义的,但在有些系统上可能会返回-1表示调用失败。数据只能从_pipe[0]中读取,数据也只能写入到_pipe[1],不能倒过来。
首先,我们在原先的进程中创建一个管道,然后再调用fork创建一个新的进程,最后通过管道在两个进程之间传递数据。父进程进行读操作,子进程进行写操作。代码如下:
#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/wait.h>int main(){ int _pipe[2]; int ret = pipe(_pipe); if(ret == -1) { printf("creat pipe error!errno code is:%d\n",errno); return 1; } pid_t id = fork(); if(id < 0) { printf("fork error!"); return 2; } else if(id==0)//child { close(_pipe[0]);//关掉读 int i = 0; char* buf = NULL; while(i<20) { if(i<10) { buf = " i am child!"; write(_pipe[1], buf,strlen(buf)+1);//写入 } sleep(1); i++; } } else//father { close(_pipe[1]);//关掉写 char buf[100]; int j = 0; while(j<3) //读取三次 { memset(buf,'\0',sizeof(buf));//清空buf int ret = read(_pipe[0],buf,sizeof(buf));//读出 printf("%s:code is %d\n",buf,ret); j++; } close(_pipe[0]); } return 0;}
命名管道(双向管道)
上述匿名管道存在一个很大的缺陷,那就是匿名管道只能用于父子进程或者说有血缘关系的进程之间,命名管道的存在就是为了解决这个缺陷。
命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似。
Linux中所有的事物都可被视为文件,所以对命名管道的使用也就变得与文件操作非常的统一,也使它的使用非常方便,同时我们也可以像平常的文件名一样在命令中使用。
#include<sys/types.h>#include<sys/stat.h>int mkfifo(const char *pathname,mode_t mode);
打开FIFO文件通常有四种方式:
1. open(const char *path, O_RDONLY); 2. open(const char *path, O_RDONLY | O_NONBLOCK); 3. open(const char *path, O_WRONLY); 4. open(const char *path, O_WRONLY | O_NONBLOCK);
在open函数的调用的第二个参数中,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的。
open调用的阻塞是什么一回事呢?很简单,对于以只读方式(O_RDONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_RDONLY),除非有一个进程以写方式打开同一个FIFO,否则它不会返回;如果open调用是非阻塞的的(即第二个参数为O_RDONLY | O_NONBLOCK),则即使没有其他进程以写方式打开同一个FIFO文件,open调用将成功并立即返回。
对于以只写方式(O_WRONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_WRONLY),open调用将被阻塞,直到有一个进程以只读方式打开同一个FIFO文件为止;如果open调用是非阻塞的(即第二个参数为O_WRONLY | O_NONBLOCK),open总会立即返回,但如果没有其他进程以只读方式打开同一个FIFO文件,open调用将返回-1,并且FIFO也不会被打开。
我们来写两个程序,server和client,让他们通过管道文件实现通信。server读出cilent写入的数据。
server.c
int main() { char buf_r[100]; int fd; int nread; printf("Preparing for reading bytes...\n"); memset(buf_r,0,sizeof(buf_r));//清空buf_r //以只读方式打开管道文件 fd=open(FIFO,O_RDONLY|O_NONBLOCK,0); if(fd==-1) { perror("open"); exit(1); } while(1) { memset(buf_r,0,sizeof(buf_r)); nread=read(fd,buf_r,100); if(nread==-1) { perror("read\n"); } printf("server read from FIFO:%s\n",buf_r); sleep(1); } close(fd); //关闭管道 pause(); /*暂停,等待信号*/ unlink(FIFO); //删除文件 }
client.c
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define FIFO_SERVER "./myfifo" int main(){ int fd; char w_buf[100]="i am client!!!"; int nwrite; int ret = mkfifo(FIFO_SERVER,O_CREAT|O_EXCL|O_RDWR); if(ret<0) { printf("create fifo failed\n"); } //以只写方式打开管道文件 fd=open(FIFO_SERVER,O_WRONLY |O_NONBLOCK,0); if(fd==-1) { perror("open"\n); exit(1); } //为管道写入数据 nwrite=write(fd,w_buf,100); if(nwrite<0) { perror("write\n"); } else { printf("write %s to the FIFO\n",w_buf); } close(fd); //关闭管道 return 0; }
- 管道(pipe、mkfifo)
- Linux c 管道文件-进程间的通信 mkfifo、pipe
- pipe popen mkfifo
- linux c学习笔记----管道文件(pipe,popen,mkfifo,pclose,dup2)
- linux学习---linux基于文件的IPC(匿名管道pipe,命名管道mkfifo,普通文件,socket文件)
- mkfifo函数创建有名管道
- shell mkfifo 阻塞式管道
- Linux_ mkfifo 命名管道 操作
- 管道pipe
- 管道 pipe
- 管道(pipe)
- 管道-pipe
- pipe管道
- pipe 管道
- pipe管道
- pipe管道
- pipe管道
- 管道 PIPE
- 从零开始搭建环境编写操作系统 AT&T GCC (六)中断设置和启用 IDT PIC
- Linux系统目录结构以及简单说明
- spring-boot
- Matlab线性规划实例
- 【博弈+找规律】HDU_4642_Fliping game
- 管道(pipe、mkfifo)
- PhpStorm中如何使用Xdebug工具
- Ant 使用教程
- Python,Pycharm,Anaconda等的关系与安装过程~为初学者跳过各种坑
- C语言之运算与表达式(笔记六)
- Proceess,Pool中的Queue通讯以及Thread中的Queue
- JavaScript学习之图片淡入淡出
- Python学习X --- 推导式
- [HDU4669]Mutiples on a circle