雪泉的专栏

:-)工作了,很少来逛了

Linux进程编程介绍(四)

Linux进程编程介绍(四)
2006-11-19 16:55

转自:计算机基础教程网(ITWEN.com)

  摘要:这一节,我们来看一种比较简单的数据传送的方法,即通过管道传送数据
  
  4.进程间使用管道通信
  
  前几节中我们讲述了有关进程的操作,我们已经学会产生一个新的进程,改变进程的执行图像等操作。然而,子进程与父进程,子进程与子进程之间,还缺少数据交换的方法。这一节,我们就来看一种比较简单的数据传送的方法,即通过管道传送数据。
  
   管道允许在进程之间按先进先出的方式传送数据,管道也能使进程同步执行。管道传统的实现方法是通过文件系统作为存储数据的地方。有两种类型的管道:一种 是无名管道,简称为管道;另一种是有名管道,也称为FIFO。进程使用系统调用open来打开有名管道,使用系统调用pipe来建立无名管道。使用无名管 道通讯的进程,必须是发出pipe调用的进程及其子进程。使用有名管道通讯的进程没有上述限制。在以后的叙述中,所有无名管道都简称为管道。下面来看一下 系统调用pipe。
  
4.1 pipe 系统调用
  
  系统调用pipe是用来建立管道的。该调用的声明格式如下:
  
    int pipe(int filedes[2]);
  
  在使用该调用的程序中加入下面的头文件:
  
    #include
  
   一个管道拥有两个文件描述符用来通信,它们指向一个管道的索引节点,该调用将这两文件描述符放在参数filedes中返回。现在的许多系统中管道允许数 据双向流动,但一般习惯上,文件描述符filedes[0]用来读数据,filedes[1]用来写数据。如果要求程序的可移植性好,就按照习惯的用法来 编程。调用成功时,返回值为0;错误时,返回-1,并设置错误代码errno:
  
  EMFILE:进程使用了过多的文件描述符。
  ENFILE:系统文件表满。
  EFAULT:参数filedes无效。
  下面介绍管道的操作的情况:
  
  对于写管道:
   写入管道的数据按到达次序排列。如果管道满,则对管道的写被阻塞,直到管道的数据被读操作读取。对于写操作,如果一次write调用写的数据量小于管道 容量,则写必须一次完成,即如果管道所剩余的容量不够,write被阻塞直到管道的剩余容量可以一次写完为止。如果write调用写的数据量大于管道容 量,则写操作分多次完成。如果用fcntl设置管道写端口为非阻塞方式,则管道满不会阻塞写,而只是对写返回0。
  
  对于读管道:
   读操作按数据到达的顺序读取数据。已经被读取的数据在管道内不再存在,这意味着数据在管道中不能重复利用。如果管道为空,且管道的写端口是打开状态,则 读操作被阻塞直到有数据写入为止。一次read调用,如果管道中的数据量不够read指定的数量,则按实际的数量读取,并对read返回实际数量值。如果 读端口使用fcntl设置了非阻塞方式,则当管道为空时,read调用返回0。
  
  对于管道的关闭:
  如果管道的读端口 关闭,那么在该管道上的发出写操作调用的进程将接收到一个SIGPIPE信号。关闭写端口是给读端口一个文件结束符的唯一方法。对于写端口关闭后,在该管 道上的read调用将返回0。下面再来看看,系统调用pipe的例子。在下面的例子中,父进程通过管道向子进程发送了一个字符串。子进程将它显示出来:
  
  #include
  #include
  #include
  #include
  #include
  int main()
  {
  int fd[2],cld_pid,status;
  char buf[200], len;
  
  if (pipe(fd) == -1)
  {
    printf("creat pipe error ");
    exit(1);
  }
  if ((cld_pid=fork()) == 0)
  {
    close(fd[1]);
    len = read(fd[0],buf,sizeof(buf));
    buf[len]=0;
    printf("Child read pipe is -- %s ",buf);
    exit(0);
  }
  else
  {
    close(fd[0]);
    sprintf(buf,"Parent creat this buff for cld %d",cld_pid);
    write(fd[1],buf, strlen(buf));
    exit(0);
  }
  }
  
  该程序执行过程的屏幕拷贝:
  
  [root@wapgw /tmp]# ./pipe
  [root@wapgw /tmp]# Child read pipe is -- Parent creat this buff for cld 5954
  [root@wapgw /tmp]#
  
4.2 dup 系统调用
  
  系统调用dup是用来复制一个文件描述符,也就是将进程u区的文件描述符表中的一项复制一份,使得这两项同时指向系统文件表的同一表项。该调用的声明格式如下:
  
    int dup(int oldfd);
    int dup2(int oldfd, int newfd);
  
  在使用该调用的程序中加入下面的头文件:
  
    #include
  
   系统调用dup复制由参数oldfd指定的文件描述到进程文件描述符表的第一个空表项处。而系统调用dup2复制由参数oldfd指定的文件描述到参数 newfd指定的文件描述符表项处。老的文件描述符和新复制的文件描述符可以互换使用。它们共享锁、文件指针和文件状态。例如,对其中一个文件描述符使用 系统调用lseek修改文件指针的位置,对另一文件描述符来说文件指针也改变了,其实我们了解了内核的工作原理,这一点很容易理解。因为我们知道,文件指 针是放在系统文件表中的。但这两个文件描述符具有不同的close-on-exec标志,因为该标志是存放在文件描述符表中的。
  
  该调用成功时,返回值为新的描述符;错误时,返回-1,并设置相应的错误代码errno:
  
  EBADF:参数oldfd不是一个已经打开的文件描述符;或者参数newfd超出允许的文件描述符的取值范围。
  EMFILE:进程打开的文件描述符数量已经到达最大值,但仍然企图打开新的文件描述符。
   下面我们来看一个简单的例子。在这个例子中,我们将标准输出(文件描述符为1)关闭,并将一个打开了普通文件“output”的文件描述符复制到标准输 出上,因为刚关闭了文件描述符1,所以,文件描述符表的第一个空表项是1。所以,程序以后的printf等向标准输出写的内容都写到了文件 output中。
  
    #include
    #include
    #include
    #include
    #include
    int main()
    {
    int fd;
    if ((fd=open("output",O_CREAT|O_RDWR,0644))==-1)
    {
      printf("cannot open output file ");
      exit(1);
    }
    close(1); /* 关闭标准输出 */
    dup(fd); /* 复制fd到文件描述符1上 */
    close(fd); /* 即时关闭不用的文件描述符是一个好习惯 */
    printf("This line will write to file ");
    exit(0);
    }
  
  该程序执行过程的屏幕拷贝:
  
    [wap@wapgw /tmp]$ gcc -o dup_test dup_test.c
    [wap@wapgw /tmp]$ ./dup_test
    [wap@wapgw /tmp]$ more output
    This line will write to file
    [wap@wapgw /tmp]$

 
阅读更多
上一篇Linux进程编程介绍(三)
下一篇为世界之光——国立交通大学校歌
想对作者说点什么? 我来说一句

linux进程编程介绍

2008年10月13日 1.03MB 下载

linux socket、驱动、进程编程

2011年04月28日 12.5MB 下载

Linux进程编程介绍.rar

2009年04月12日 861KB 下载

Linux 进程编程介绍.zip

2008年12月30日 868KB 下载

Linux进程编程介绍

2007年12月22日 987KB 下载

linux 进程控制阅读笔记

2009年03月11日 18KB 下载

linux 初级 c编程

2010年02月12日 537KB 下载

没有更多推荐了,返回首页

关闭
关闭