管道

来源:互联网 发布:php连接sql server 编辑:程序博客网 时间:2024/06/08 19:43

 

管道

管道是UNIX系统IPC的最古老形式,并且所有UNIX系统都提供此种通信机制。但是管道有两种局限性:

1、  历史上它们是半双工的。现在某些系统提供全双工的。

2、  它们只能在具有公共祖先的进程之间使用。通常一个管道由一个进程创建,然后该进程调用fork,此后父子进程之间就可以应用该管道。

尽管有这两个限制,半双工管道仍是最常用的IPC形式。

 

一、创建管道函数pipe

#include <unistd.h>
int pipe(int filedes[2]);

returns: 0 if OK, 1 on error

filedes[2]:它返回两个描述符,filedes[0]:为读打开;filedes[1]:为写打开。filedes[1]的输入是filedes[0]的输出。

 

1、  构造父进程到子进程的管道

父进程关闭管道的读端filedes[0],子进程关闭写端filedes[1]

 

2、  构造子进程到父进程的管道

子进程关闭管道的读端filedes[0],父进程关闭写端filedes[1]

 

3、  示例

示例1:创建一个从父进程到子进程的管道

#include "apue.h"
 
int
main(void)
{
    int     n;
    int     fd[2];
    pid_t   pid;
    char    line[MAXLINE];
 
    if (pipe(fd) < 0)
        err_sys("pipe error");
    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {       /* parent */
        close(fd[0]);
        write(fd[1], "hello world/n", 12);
    } else {                /* child */
        close(fd[1]);
        n = read(fd[0], line, MAXLINE);
        write(STDOUT_FILENO, line, n);
    }
    exit(0);
}
 
示例2:两个进程间的管道模型   #include <stdio.h>     
#include <unistd.h>     
#include <string.h>     
#include <wait.h>     
     
#define MAX_LINE        80     
     
int main()     
{     
int thePipe[2], ret;     
char buf[MAX_LINE+1];     
const char *testbuf={"a test string."};     
    
if ( pipe( thePipe ) == 0 ) {     
    
           if (fork() == 0) {    
            close(thePipe[1]); 
            ret = read( thePipe[0], buf, MAX_LINE );     
             buf[ret] = 0;     
             printf( "Child read %s/n", buf );     
     
           } else {     
             close(thePipe[0]);
             ret = write( thePipe[1], testbuf, strlen(testbuf) );     
             ret = wait( NULL );     
     
           }     
     
}     
     
return 0;     
}

 

示例3:利用C实现命令的流水线操作  
       #include <stdio.h>    
       #include <stdlib.h>    
      #include <unistd.h>    
   
      int main()    
       {    
        int pfds[2];    
    
        if ( pipe(pfds) == 0 ) {    
    
           if ( fork() == 0 ) {    
   
           close(1);    
             dup2( pfds[1], 1 );    
            close( pfds[0] );    
            execlp( "ls", "ls", "-1", NULL );    
    
          } else {    
   
            close(0);    
           dup2( pfds[0], 0 );    
            close( pfds[1] );    
             execlp( "wc", "wc", "-l", NULL );    
   
           }    
    
        }    
    
        return 0;    
       }

    
在该程序中,需要格外关注的是,我们的子进程把它的输出重定向的管道的输入,然后,父进程将它的输入重定向到管道的输出。这在实际的应用程序开发中是非常有用的一种技术。

 

二、打开和关闭管道函数popenpclose

常见的操作是创建一个管道,然后连接到一个进程,然后读其输出或向其输入端发送数据。

popen()函数通过创建一个管道,调用 fork产生一个子进程,执行一个 shell以运行命令来开启一个进程。

这个进程必须由 pclose() 函数关闭,而不是 fclose()函数。pclose()函数关闭标准 I/O流,等待命令执行结束,然后返回 shell的终止状态。如果 shell不能被执行,则 pclose()返回的终止状态与 shell已执行 exit一样。

#include <stdio.h>
FILE * popen ( const char * command , const char *type );

intpclose ( FILE * stream );

如果调用 fork() pipe()失败,或者不能分配内存将返回NULL,否则返回标准 I/O 流。

示例:
if((fp=popen("/usr/bin/uptime","r"))==NULL);

{

  sprintf(buf,"error: %s/n", strerror(errno));

  ....//异常处理

  }

  else

  {

  ....

  pclose(fp);

  }