• UNIX网络编程卷2进程间通信读书笔记(二)—管道 (1)


    一.管道

           管道的名称很形象,它就像是一个水管,我们从一端到水然后水从令一端流出。不同的是这里说的管道的两边都是进程。从一端往管道里写数据,其它进程可以从管道的另一端的把数据读出,从而实现了进程间通信的功能。

           管道是Linux支持的最初Unix IPC形式之一,具有以下特点:

           1.管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

           2只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

           单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

           数据的读出和写入:管道是半双工的,数据只能在一个方向上流动。一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

    1.1管道的创建

           管道是由调用pipe函数而创建的。

    1

    名称:

    pipe

    功能:

    创建管道

    头文件:

    #include <unistd.h>

    函数原形:

    int pipe(int filedes[2]);

    参数:

     

    返回值:

    若成功返回0,若出错则返回-1

         

     

    Linux用函数pipe来创建管道,经由参数filedes返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。

     

     

    /*14_1.c*/
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
     
    int main()
    {
    int n;
    int fd[2];
    pid_t pid;
    char line[1024];
     
    if(pipe(fd)<0) /*建立管道*/
        perror(“pipe error”);
    if((pid=fork())<0) /*创建子进程*/
        perror(“fork error”);
    else if(pid==0) /*如果是子进父程*/
    {
        close(fd[0]); /*关闭读描述符*/
        write(fd[1],”I’m child,hello father!”,23);/*往管道里写数据*/
    }
    else  /*如果是父进程*/
    {
        close(fd[1]); /*关闭写描述符*/
        wait(); /*等待子进程结束*/
        n=read(fd[0],line,1024); /*从管道里读数据,读到缓冲数组中*/
        write(STDOUT_FILENO,line,n); /*把缓冲区的数据写道屏幕上*/
    }
    exit(0);
    }

     注意,默认情况下,read函数回阻塞到有数据可读为止。


    程序先创建一个管道,而后创建一个子进程。让父进程向管道里写数据,让子进程从管道读数据,程序在写个读之前都把不用的描述符关掉。这要做的好处是提高了安全性,因为如果父子进程同时往管道里写将发生错误。
    程序的运行结果是 I’m father, hello child!

     

    1.2管道的读写规则

           管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如closereadwrite等等。

           从管道中读取数据:如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。

           向管道中写入数据:向管道中写入数据时,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

    注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

    1.3管道的局限性

    管道的主要局限性正体现在它的特点上:

    只支持单向数据流;

    只能用于具有亲缘关系的进程之间;

    没有名字;

    管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);

    管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;

     

    1.4管道的其它操作函数

     

    poen pclose创建和关闭无名管道

     

    Linux下标准I/O函数库提供了poen函数,它创建了一个管道并启动另外一个进程,该进程或者从管道读出标准输入,或者从管道写入标准输出。

     

    #include <stdio.h>

    FILE *poen(const char *command,const char *type); 

    //返回:成功时为文件指针,出错时为NULL

     

    int pclose(FILE *stream);

    //返回:成功时为shell的终止状态,出错时为-1

     

     

    其中command是一个shell命令行,它是由shell程序处理的,poen在调用进程和所指定的命令之间创建一个管道,由open返回的值是一个标准I/O FILE指针,该指针或者用于输入,或者用于输出,具体取决于字符串type,如果typer,那么调用进程读取command的标准输出。如果typew,那么调用进程写到command的标准输入。pclose函数关闭由poen创建的标准I/Ostream,等待其中的命令终止,然后返回shell的终止状态。

     

      

     

     

    这两个函数执行过程是:先创建一个管道,调用fork产生一个子进程,然后关闭管道的不使用端,执行一个shell以运行命令,然后等待命令终止。

    函数popen先执行fork,然后调用exec以执行cmdstring,并且返回一个标准I/O文件指针。如果type“r”,则文件指针连接到cmdstring的标准输出。如果type”w”,则文件指针连接到cmdstring的标准输入。

  • 相关阅读:
    Mysql中varchar类型的猫腻!
    震惊!java中日期格式化的大坑!
    mysql数据库限制多次登录失败,限定用户重试时间
    2021年回顾与展望
    多线程循环打印abc
    2020年总结-用学习过的技术搭建一个简单的微服务框架 + 源码
    回溯算法
    PyTorch 中 weight decay 的设置
    数据结构与算法——计数排序
    数据结构与算法——堆排序
  • 原文地址:https://www.cnblogs.com/diegodu/p/4024513.html
Copyright © 2020-2023  润新知