1.管道基本概念
管道是针对于本地计算机的两个进程之间的通信而设计的通信方法,管道建立后,实际获得两个文件描述符:一个用于读取而另外一个用于写入。
管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管道。
无名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。 命名管道单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是单独构成一种文件系统。
数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
2.管道基本概念二
管道通信:是利用FIFO排队模型来指挥进程间的通信。把它当作是连接两个实体的一个单向连接器
使用管道的命令实例: ls -1 | wc -l 该命令首先创建两个进程,
一个对应于ls –1,另一个对应于wc –l。
然后,把第一个进程的标准输出设为第二个进程的标准输入。它的作用是计算当前目录下的文件数量。
3.无名管道

4.无名管道的特点:
1.只能用于具有亲缘关系的进程之间的通信
2.半双工的通信模式
3.具有固定的读端和写端 管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数。
5.管道创建与关闭
管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。
其中fd[0]固定用于读管道,而fd[1]固定用于写管道。 构成了一个半双工的通道。

6.无名管道的创建 函数
pipe(建立管道)
头文件 #include
定义函数 int pipe(int filedes[2]);
函数说明 pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。
返回值 若成功则返回0,否则返回-1,错误原因存于errno中。
错误代码 EMFILE 进程已用完文件描述词最大量。
ENFILE 系统已无文件描述词可用。
EFAULT 参数filedes数组地址不合法。
7.代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:管道的功能
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
-
- //1.pipe 管道功能的使用
- //功能:创建一个管道
- //参数: int fds[[2]
- //返回值 : 0成功 -1失败
- //
-
-
- //2.创建一个管道 ,并且在尾部写入,头部读取
- //
- int main(int argc,char *argv[])
- {
- int fds[2]={0};
- //创建一个管道
- if(pipe(fds)<0)
- {
- printf("%d %s\n",errno,strerror(errno));//strerror函数的作用就是将错误码给转化成错误信息。
- }
- printf("read fds[0] =%d\t write fds[1]=%d\n ",fds[0],fds[1]);
- char buff[100]={"你abc"};
- int a =strlen(buff);
- printf("字符串的长度: %d\n",a);
- int len =write(fds[1],buff,strlen(buff)); //写入数据到 写端
- printf("len =%d\n",len);
-
- bzero(buff,sizeof(buff));//清空字符数组
- len =read(fds[0],buff,sizeof(buff));//读一下
- printf("buff is %s len= %d\n",buff,len);
- close(fds[0]);
- close(fds[1]);
- return 0;
-
- }
8.程序功能:父子进程之间的管道操作
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:父子进程之间的管道操作 多次
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- //多次读写
- //
- int main(int argc,char *argv[])
- {
- int fds[2]={0};
- if(pipe(fds)<0)//创建管道
- {
- printf("%d %s \n",errno,strerror(errno));
- return -2;
- }
-
- char buff1[100]={"abcdefg"};
- pid_t pid =fork();
- if(pid <0)
- {
- perror("fork error\n");
- return -1;
- }
- else if(pid ==0)//子进程
- {
-
- //char buff1[100]={"abcdefg"};
- int len =write(fds[1],buff1,strlen(buff1)); //写入数据 第一次
- if(len<0)
- {
- printf("write error\n");
- }
- else
- {
- printf("write :len :%d\n",len);
- }
- len =write(fds[1],buff1,strlen(buff1)); //写入数据 第二次
- if(len<0)
- {
- printf("write error\n");
- }
- else
- {
- printf("write :len :%d\n",len);
- }
- }
- else if(pid >0) //父进程
- {
- wait(NULL);
- char buff[100];
- bzero(buff,sizeof(buff));
- int len1 = read(fds[0],buff,sizeof(buff));
- if(len1<0)
- {
- perror("read error\n");
- }
- else
- {
- printf("read : %s\n",buff);
- }
- }
-
-
- return 0;
-
- }
9.程序功能:父子进程 无名管道 多次写 一次读
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- //1.popen pclose
- //2.popen 高级管道 标准管道
- //3.
- int main(int argc,char *argv[])
- {
- //fp 是标准管道流指针
- FILE * fp =popen("ls -l","r");//r 可读的方式
- if(fp==NULL)
- {
- printf("%d %s\n",errno ,strerror(errno));
- return -2;
- }
- char buff[1024]="";
- fread(buff,1024,1,fp);
- fwrite(buff,strlen(buff),1,stdout);
- pclose(fp);
-
- return 0;
-
- }
10.//1.popen pclose 函数
popen(建立管道I/O)
头文件 #include
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。
返回值 若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
错误代码 EINVAL参数type不合法。 注意事项 在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。
pclose(关闭管道I/O)
头文件 #include
定义函数 int pclose(FILE * stream);
函数说明 pclose()用来关闭由popen所建立的管道及文件指针。
参数stream为先前由popen()所返回的文件指针。
返回值 返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。
错误代码 ECHILD pclose()无法取得子进程的结束状态。

代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- //1.popen pclose
- //2.popen 高级管道 标准管道
- //3.
- int main(int argc,char *argv[])
- {
- //fp 是标准管道流指针
- FILE * fp =popen("ls -l","r"); //r 可读的方式
- if(fp==NULL)
- {
- printf("%d %s\n",errno ,strerror(errno));
- return -2;
- }
- char buff[1024]="";
- fread(buff,1024,1,fp);
- fwrite(buff,strlen(buff),1,stdout); //写到屏幕上
- pclose(fp);//关闭管道
-
- return 0;
-
- }
11.mkfifo 创建有名管道
头文件 #include
定义函数 int mkfifo(const char * pathname,mode_t mode);
函数说明 mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限,因此mode值也会影响到FIFO文件的权限。当使用open()来打开FIFO文件时O_NONBLOCK旗标会有影响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。反之亦是如此

代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:mkfifo 创建有名管道
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- //有名管道
- //1.程序运行结束之后 有具体的文件存在
- //2.非亲缘之间也可以进行通信
- //3.没有固定的读写端
- //4.无名有名管道 都不可以用lseek 来定位
- //文件必须不存在
- //读写必须同步,写完就读 ,否则在短时间(进程结束以后)内会消失
- //
- int main(int argc,char *argv[])
- {
- char str[100]={"pipe"};
- if(mkfifo(str,0666)<0)
- {
- perror("mkfifo error\n");
- return -1;
- }
- else
- {
- printf("mkfifo ok\n");
- }
- int fd=open(str,O_RDWR);
- char buff[2000]={"-----------------------\n"};
- write(fd,buff,strlen(buff));
- char buff1[200]="";
- read(fd,buff1,sizeof(buff));
- fputs(buff1,stdout);
- unlink(str); //删除文件 pipe
-
- return 0;
-
- }
12.程序 :测试系统 有多少个文件描述符号
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:有多少个文件描述符号
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- int main(int argc,char *argv[])
- {
- int fd=0;
- while((fd=open("a.txt",O_CREAT|O_RDWR,0666))!=-1)
- {
- printf("fd =%d\n",fd);
- }
-
-
- return 0;
-
- }