linux管道

来源:互联网 发布:c语言编写的小程序 编辑:程序博客网 时间:2024/05/16 01:20

linux 管道 

管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。

有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建。

Linux管道的实现机制

管道机制两端必定连接着两个进程,向管道写入数据的进程称为写管段进程。从管道读出数据的进程称为读管道进程,linux管道机制是单向的,一旦确定了数据传送方向,就不能更改。数据在管道式以先进先出的方式传送数据,

在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:

·      限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不象文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。

·      读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。

注意:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。

1. 管道的结构

     在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。

2.管道的优点

信号在进程之间传递的只是一个信号值,而管道能够传送大量的数据。

3 .管道与文件的区别

根本区别在与管道使用的不是外存,而是实在的物理内存存储数据

4. 命名管道与文件的区别

命名管道不是使用磁盘的数据区存放数据而是内存的缓冲区存放数据

管道读写

首先介绍pipe( )函数,

pipe()函数语法要点

头文件  #include<unistd.h>

函数原型  int pipe(int fd[2])

函数传入值fd[2] :管道的两个文件描述符,之后就可以直接操作这两个文件描述符

函数返回值   成功 :0   出错 -1

例子:
#include<stdio.h>
#include<unistd.h>

#define MAX_DATA_SIZE 1024
int main()
{
int n,fd[2];                         // 这里的fd是文件描述符的数组,用于创建管道做准备的
pid_t pid;
char data[MAX_DATA_SIZE];
if(pipe(fd)<0)                     //   创建管道
   printf("pipe create error/n");

if((pid=fork())<0)              //利用fork()创建新进程
    printf("fork error/n");

else if(pid>0){                   //这里是父进程,先关闭管道的读出端,然后在管道的写端写入“hello world"
    close(fd[0]);

sleep(1);//等待子进程关闭写入端,因为,这个程序的父子进程运行先后次序不知
  write(fd[1],"hello word/n",11);

}
else{
    close(fd[1]);                 //这里是子进程,先关闭管道的写入端,然后在管道的读出端读出数据

  sleep(3);//等待父进程,关闭管道的读出段

   n= read(fd[0],data,MAX_DATA_SIZE);
    write(STDOUT_FILENO,data,n); //输出到终端界面

}
exit(0);
}

标准流管道  :

是基于文件流的标准I/O操作一样,管道操作也支持文件流的模式。,这种基于文件流的管道主要是用来创建一个连接到另一个进程的管道,这里的“另一个进程”也就是一个可以进行一定操作的可执行文件,例如,用户执行“ls -l”或者自己编写的程序 ,只不过标准的管道读写要用标准的读写文件函数,

这里创建管道的函数为popen(),这个函数所完成的工作如下:

创建一个管道

fork()一个子进程

在父子进程中关闭不需要的文件描述符

执行exec函数族调用。

执行函数中所指定的命令

这个函数能够大大减少代码的编写量,但同时也有些不利之处。

关闭popen()创建的流管道必须要用pclose()来关闭该管道流该函数关闭标准I/O流,并等待命令执行结束。

函数原型 FILE * popen ( const char * command , const char * type );

intpclose ( FILE* stream );

popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。这个进程必须由 pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。
type 参数只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 "r" 则文件指针连接到 command 的标准输出;如果 type 是 "w" 则文件指针连接到 command 的标准输入。
command 参数是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用-c 标志,shell 将执行这个命令。
popen 的返回值是个标准 I/O 流,必须由 pclose 来终止。前面提到这个流是单向的。所以向这个流写内容相当于写入该命令的标准输入;命令的标准输出和调用 popen 的进程相同。与之相反的,从流中读数据相当于读取命令的标准输出;命令的标准输入和调用 popen 的进程相同。

0 0
原创粉丝点击