`
tomotoboy
  • 浏览: 166818 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

进程间通信——管道

阅读更多
1.匿名管道
匿名管道创建的四种方法
  • 使用pipe()函数
  • 使用dup()函数
  • 使用dup2()函数
  • 使用popen()/pclose()函数


dup()函数
有时候我们需要将子进程当中的管道的句柄定向到标准 I/O(stdin/stdout)上去。这样,在子进程中使用 exec()函数调用外部程序时,这个外部程序就会将管道作为它的输入/输出。这个过程可以用系统函数 dup()来实现。
下面是它的原型:
int dup( int oldfd);

虽然原句柄和新句柄是可以互换使用的,但为了避免混淆,我们通常会将原句柄关闭(close) 。同时要注意,在 dup()函数中我们无法指定重定向的新句柄,系统将自动使用未被使用的最小的文件句柄(记住,句柄是一个整型量)作为重定向的新句柄。


dup2()函数
在 Linux 系统中还有一个系统调用函数 dup2()。单从函数名上我们也可以判断出它和 dup()函数的渊源。dup2 将用 oldfd 文件描述符来代替 newfd 文件描述符,同时关闭 newfd 文件描述符.也就是说, 所有向 newfd 操作都转到 oldfd 上面.
下面是它的原型:
int dup2( int oldfd, int newfd );

注意:旧句柄将被 dup2()自动关闭。显然,原来的 close 以及 dup 这一套调用现在全部由 dup2()来完成。这样不仅简便了程序,更重要的是,它保证了操作的独立性和完整性,不会被外来的信号所中断。在原来的dup()调用中,我们必须先调用close()函数。假设此时恰好一个信号使接下来的 dup()调用不能立即执行,这就会引发错误(进程没有了 stdin) 。使用 dup2()就不会有这样的危险。





2.有名管道的I/O使用
有名管道和管道的操作是相同的,只是要注意,在引用已经存在的有名管道时,首先要用系统中的文件函数来打开它,才能接下来进行其他的操作。例如,我们可以用操作文件流的fopen()和fclose()来打开一个有名管道。下面是一个server 方的例子:
/* fifoserver.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#define FIFO_FILE  " sampleFIFO"
int main(void)
{
        FILE *fp;
         char readbuf[80];
        /* Create the FIFO if it does not exist * /  
        umask(0);
        /*在文件系统中创建有名管道*/
         mknod(FIFO_FILE, S_IFIFO|0666, 0);
         while(1)
         {
                 /*打开有名管道*/
                 fp = fopen(FIFO_FILE, "r");
                 /*从有名管道中读取数据*/
                 fgets(readbuf, 80, fp);
                 printf("Received string: %s\n", readbuf);
                 /*关闭有名管道*/
                 fclose(fp);
         }
          return(0);
}

因为有名管道自动支持进程阻塞,所以我们可以让这个 server 在后台运行:
#fifoserver &

然后运行下面的 client 程序:
#include <stdio.h>
#include <stdlib.h>
#define FIFO_FILE       "sampleFIFO"
int main(int argc, char *argv[])
{
        FILE *fp;
         if ( argc != 2 ) {
                 printf("USAGE: fifoclient [string]\n");
                 exit(1);
        }
         /*打开有名管道*/
         if((fp = fopen(FIFO_FILE, "w")) == NULL) {
                 perror("fopen");
                 exit(1);
        }
         /*向有名管道中写入数据*/
         fputs(argv[1], fp);
         /*关闭有名管道*/      


         fclose(fp);
         return(0);
}
由于有名管道的自动阻塞特性,当上面的 server 打开一个有名管道准备读入时,server进程就会被阻塞以等待其他进程(在这里是我们的 client 进程)在有名管道中写入数据。反之亦然。不过,如果需要,我们也可以在打开一个有名管道时使用 O_NONBLOCK标志来关闭它的自动阻塞特性。


未提到的关于有名管道的一些注意
首先,有名管道必须同时有读/写两个进程端。如果一个进程试图向一个没有读入端进程的有名管道写入数据,一个 SIGPIPE信号就会产生。这在涉及多个进程的有名管道通信中是很有用的。

其次,关于管道操作的独立性。一个“独立”的操作意味着,这个操作不会因为任何原因而被中断。比如,在 OSIX 标准中,头文件/usr/include/posix1_lim.h中定义了在一次独立的管道读/写操作中最大传输的数据量(buffer size):
#define _POSIX_PIPE_BUF         512

也即是说,在一次独立的管道读/写操作中最多只能传送 512 个字节的数据,当数据量超过这个上限时操作就只能被分成多次独立的读/写操作。在 Linux 系统中,头文件“ linux/limits.h” 中定义了类似的限制:
#define PIPE_BUF                4096

可以看出,和 POSIX 标准比,上限被大大增加了。这在涉及多进程的有名管道操作中是非常重要的。如果在某个进程的一次写操作中传输的数据量超过了独立读/写操作的数据量上限,这个操作就有可能被别的进程的写操作打断。也就是说,别的进程把数据插入了该进程写入管道的数据序列中从而造成混乱。这是在有名管道应用中需要特别注意的。



参考资料:
《linux网络编程》李卓恒等译
分享到:
评论

相关推荐

    实验一 进程通信——管道和信号实验报告.doc

    【进程间通信:管道通信】 实验还涉及到管道(pipe)通信。通过pipe()函数创建一个单向的数据通道,使得两个进程可以通过这个通道交换信息。在这个例子中,父进程创建两条管道,子进程P1和P2分别向各自的管道写入...

    进程间通信——管道读

    进程间通信,管道方式,文件用于读取管道内容,并写文件

    操作系统实验五-进程间通信-管道通信

    操作系统实验五 进程间通信——管道通信 无名管道 有名管道 write()和read() pipe() 函数int pipe(int fd[2])创建一个管道 lockf()函数使用管道通信时,可关闭某些不需要的读或写描述符wait()、waitpid(),sys/wait....

    进程间通信——匿名管道

    总结来说,匿名管道是进程间通信的基础工具,尤其适用于简单的单向通信场景。尽管它的功能有限,但其高效和简洁的特性使其在许多早期的系统设计中占据一席之地。理解并熟练掌握匿名管道的使用,对于深入理解操作系统...

    进程通信——管道通信

    管道通信是早期操作系统中引入的一种简单而有效的进程间通信(IPC, Inter-Process Communication)方式。它创建了一个单向的数据流通道,允许一个进程(生产者)将数据写入管道,然后被另一个进程(消费者)读取。在...

    实验四:Linux下进程管道通信.docx

    实验的目标是理解和掌握Linux操作系统中进程间通信的管道机制,通过系统调用pipe()实现数据交换。管道是一种特殊类型的文件,它允许相关进程之间进行单向通信。在这个实验中,我们关注三个具体任务。 ### 任务1 这...

    实验一-进程通信——管道和信号实验报告.doc

    ### 实验一 进程通信——管道和信号实验报告 #### 实验背景及目标 本实验旨在通过实际操作深入理解进程通信的相关概念和技术,特别是管道和信号这两种进程间通信方式。实验目标具体包括: 1. **加深对进程概念的...

    Linux进程间通信4——使用命名管道.doc

    ### Linux 进程间通信 4 —— 使用命名管道 #### 一、引言 在上一篇文章中,我们探讨了如何利用匿名管道实现进程间的数据传递,并提到了匿名管道的一个限制:即所有通信的进程必须是由同一个祖先进程派生出来的。...

    LINUX高级程序设计(中文第二版)

    第八章的主题是“进程间通信——管道和信号”,这一部分是Linux系统编程的核心内容之一,对于理解和实现多进程协同工作至关重要。 在Linux环境中,进程间通信(IPC,Inter-Process Communication)是多个独立运行的...

    进程间通信之套接字( socket )——完整代码

    进程间通信之套接字( socket ) 网络间通信 七种进程间通信方式: 一.无名管道( pipe ) 二.有名管道( fifo ) 三.共享内存 ( shared memory ) 四.信号 ( sinal ) 五.消息队列 ( message queue ) 六.信号量 ( ...

    进程间通信之消息队列 ( message queue )——完整代码

    进程间通信之消息队列 ( message queue ) 消息队列是消息的链表,具有特定的格式,并由消息队列标识符标识. 七种进程间通信方式: 一.无名管道( pipe ) 二.有名管道( fifo ) 三.共享内存 ( shared memory ) 四....

    实验三、进程通信(一)——管道及共享内存.pdf

    匿名管道用于具有亲缘关系的进程之间,通常是父子进程间通信。命名管道则可用于任何两个进程间的通信,即使这两个进程没有亲缘关系。 在给定文件的内容中,我们可以看到对匿名管道的实现。通过调用pipe函数创建了一...

    高级进程间通信问题——快速排序问题1

    【高级进程间通信问题——快速排序问题1】的实验是一个基于操作系统原理的编程挑战,旨在实现一个多线程或多进程的快速排序算法。这个实验在Ubuntu 18.04.5 LTS环境下进行,采用C/C++编程语言,并且允许使用C++11的...

    MFC教程lesson 17-进程间通信.rar

    本教程聚焦于MFC中的一个重要概念——进程间通信(Inter-Process Communication,IPC)。进程间通信允许不同的进程之间交换数据,共享资源,协同工作,是Windows编程中的关键技能。Lesson 17的MFC教程将深入探讨这一...

    操作系统实验——进程创建与进程间通信

    三、进程间通信(管道) 进程间通信(IPC, Inter-Process Communication)是操作系统中实现不同进程间数据交换的关键技术。管道是一种半双工通信方式,数据只能单向流动。在Linux中,通过`pipe()`函数可以创建一个...

    Linux进程间通信(一)——Sam用图概述

    无名管道主要用于具有亲缘关系的进程间通信,而有名管道则可以在不相关的进程间通信。 2. **信号量**:信号量是一个整型变量,用于解决多个进程访问同一资源的互斥和同步问题。它可以是计数信号量,用于控制对资源...

    linux高级程序设计Part2

    首先,第八章“进程间通信——管道和信号”详细讲解了如何在不同的进程之间交换数据。管道是一种简单而有效的方法,允许相关进程共享数据流。它由一个写端和一个读端构成,数据按照先进先出的原则传输。信号则是进程...

    第七章进程间通信1

    本章主要关注管道通信和System V IPC,而完全网络兼容的进程间通信——Socket将在第十三章涉及。 **管道通信**是最简单的进程间通信形式之一。它通过一个共享文件(或称为pipe文件)连接读进程和写进程,允许数据以...

Global site tag (gtag.js) - Google Analytics