linux下管道问题
来源:互联网 发布:数据库和数据源的关系 编辑:程序博客网 时间:2024/06/05 07:34
一、管道含义
对于管道,它是一种半双工的通信机制,也就是说,他只能一端用来读,另一端用来写; 管道通信遵循先进先出的原理,并且数据只能被读取一次,当此段数据被读取后,马上会从数据中消失。(写入的数据每次都添加到管道缓冲区的末尾,读数据的时候都是从缓冲区的头部读出数据的。)
按照管道的类别分有两种管道,匿名的和命名的;按照管道的传输方向分也可以分成两种,单向和双向的。根据管道的特点,命名管道通常用在网络环境下不同计算机上运行的进程之间的通信(当然也可以用在同一台机的不同进程中)它可以是单向或双向的;匿名管道只能用在同一台计算机中,它只能是单向的。
管道是一种最基本的IPC机制,是由pipe函数创建,当其执行后,会产生两个文件描述符,分别为读短和写端,单个进程中的管道几乎没有作用,通常先调用pipe函数,然后调fork函数,从而创建从父进程到子进程的IPC管道。管道的生命周期随进程,管道给不同进程提供同步与互斥的功能 。
二、管道的通信
管道两端的任务是固定的,一端只能用于读,有描述符fd[0]表示,称其为管道读端;另一端只能用于写,由描述符fd[1]来表示,称其为管道写端;
通信方式:1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端;
2、父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道;
3、父进程关闭管道读端,子进程关闭管道写端。父进程向管道里写数据,子进程可以从管道内读数据。数据从写端流入从读端流出,这样就实现了父子进程之间的通信。
三、(匿名)管道的简单实现
从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:
1、 限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不像文件那样不加检验地增长。总缓冲区大小:64K。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,那么只有等待某些数据被读取,以便腾出足够的空间供write()调用写。
2、读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,只有等待某些数据被写入。
#include <unistd.h> #include <stdio.h> int main() { int fd[2]; //管道入口fd[0]为读,fd[1]为写入口 char r_buf[100]; char w_buf[20]= "hello word!"; pid_t pid; if(pipe(fd) < 0) { printf("pipe error!\n"); exit(1); } if((pid = fork()) < 0) { printf("fork error!\n"); }else if(pid == 0) //child { printf("child\n"); close(fd[1]); //关闭写端口 sleep(2); //程序休眠2秒 read(fd[0], r_buf, 100);//读阻塞,当管道内写入东西后才读取,所以当主程序运行完成后,子程序才运行完成。子程序由init管理 printf("%s",r_buf); }else //主进程 { printf("father\n"); close(fd[0]); sleep(2); write(fd[1], w_buf, 20); } return 0; }使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置 O_NONBLOCK 标志):
1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次 read 会返回0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次 read 会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write ,那么该进程会收到信号 SIGPIPE ,通常会导致进程异常终止。
4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次 write 会阻塞,直到管道中有空位置了才写入数据并返回。
四、命名管道
管道(匿名管道)的一个不足之处就是没有名字,因此,只能用于具有亲缘关系的进程间通信,在命名管道(name pipe或FIFO)提出后,该限制得到了解决。FIFO不同与管道之处在与她提供一个路径名与之关联,以FIFO的文件形式存储在文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信了。值得注意的是FIFO(First In First Out)总是按照先进先出的原则工作,第一个被写入的数据首先从管道中读出。
Linux下有两种方式创建命名管道。一是在Shell下交互地建立一个命名管道,二是在程序中使用系统函数建立命名管道。Shell方式下可使用mknod或mkfifo命令,下面命令使用
mknod创建了一个命名管道:
mknod namedpipe
创建命名管道的系统函数有两个:mknod和mkfifo。
int mknod(const char *pathname, mode_t mode, dev_t dev);
int mkfifo( const char *pathname, mode_t mode );
函数mknod参数中pathname为创建有名管道的全路径名,mode为创建命名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,它只在创建设备文件是才会用到。这两个函数调用成功都返回0,否则返回-1.读写命名管道:
ssize_t read (int fd , void * buf , size_t nbytes)
ssize_t write (int fd , void * buf , size_t nbytes)
五、管道的环形缓冲区
每个管道只有一个页面作为缓冲区,该页面是按照环形缓冲区的方式来使用的。
这种方式就像生产者和消费者问题:
- linux下管道问题
- linux下管道
- linux下管道通信
- linux下管道命令|
- Linux下实现管道
- linux下的管道
- linux下管道读写阻塞的相关问题
- linux 下管道的使用
- linux 下有名管道读写
- Linux下的管道编程
- Linux下的管道编程
- Linux下的无名管道
- Linux下的管道通信
- Linux下的管道通信
- linux下进程间通信系列(管道和命名管道)
- Linux下的管道pipe----管道容量和实现机制
- Linux下使用使用管道时多个参数的问题的解决方案
- linux下的管道通信程序
- hdu4651
- 在Linux中让echo命令显示带颜色的字。
- leetcode125. Valid Palindrome
- 螺旋矩阵
- 前端开发资源汇总分享(一)
- linux下管道问题
- Nircmd命令速查 与 速用,配合PowerPro使用
- ImageLoader加载图片
- Android官方数据绑定框架DataBinding
- 349. Intersection of Two Arrays
- hdu 4004 The Frog's Games 二分+贪心
- java.lang.NoSuchMethodException: MapReduce.WordCount$MyMapper.<init>()
- Spring4+SpringMVC4+Jackson2+Hibernate4+Quartz2+Plupload2+Proxool0.9集成
- 神经网络图灵机(Neural Turing Machines, NTM)