Linux进程线程学习笔记:进程间通信之 管道

    xiaoxiao2025-09-15  889

    中秋和国庆长假连起来耍了19天,平时学的点东西都快全忘了,那么赶紧补习下Linux吧。

    所谓“进程间通信(IPC,inter-process communication)”,按照其目的讲就是让进程之间能够“共享数据”,“传输数据”,“事件通知”,“进程通知”等,我所知道的一共有“管道” “信号” “消息(报文)” “共享内存” “套接字” 这几种方式,我们会挨个挨个说,今天就说说管道。

    所谓管道嘛,顾名思义类似于我们生活中的水管,只不过其中流动的是“数据”或者说一个一个字节,只能单向流动的我们称为“半双工”,能双向流动的称为“全双工”,其有两个端点,数据流入的那一端称为“写端”,反之则称为“读端”,这两个端点实际上是两个“描述字”。这样的管道可以连接在两个进程之间,成为数据传输的通道。

    按照是否有名字,管道分为“未命名管道”也就是你经常看到的pipe,以及“有名管道”也就是你经常看到的FIFO(first in first out, 和数据结构中的FIFO一样,其也是按照“先进先出”的法则传输数据)。

     

    1,pipe

    pipe一词虽然是“管道”二字的英文翻译,但在这里其不是管道的统称,而是一种最基本和简单的管道形式:未命名管道。由于其没有名字(或者说id之类的),所以其无法在两个毫无干系的两个进程间使用。试想一下,进程A创建了一个管道,进程B无法去找到该管道并使用它,因为没有任何可拿去查找的凭据,连名字都没有... 但在一种特殊情况下其是有用的,如下图,假设进程A创建了一个管道:

      

    其中的箭头代表数据写入和读出,很明显,进程A可以从管道的写端将数据写入,然后再从读端读出,但这似乎没有什么意义。 但,如果在管道建立以后,我们将进程A进行一次fork(),有意思的事情发生了, 子进程会复制父进程的大部分信息,这些信息里当然包含了代表了管道读端和写端的两个“描述字”(但管道仍然只有一份,就像被两个进程读写的某个硬盘文件只有一份一样),所以其就演变成下图这个样子:

     如果此时,我们将上图中左上角以及右下角的两个箭头抛弃掉(相当于是说将这两个箭头所对应的描述字关闭), 那么就如下所示咯:   

    哈,注意到了吗?我们建立了一个从进程A流向进程B的数据通道。

     

    那么,将上述过程写成代码的形式就很简单了。

    首先是 int pipe(int f[2]) 这个函数,其需要头文件<unistd.h>,这个函数将创建一个未命名管道,并将管道的读端描述字包含在f[0]中,将写端描述字放在f[1]中,然后你就可以像利用普通文件描述字一样来读写数据了。

    然后是fork函数,不多讲,不了解的同学一定要先搞清楚了,比如看这篇文章。 再次是int close(int fd) 函数, 其需要头文件<unistd.h>,其用于关闭指定的文件描述字。

    最后是write和read函数, 其需要头文件<unistd.h>,用于读写数据。

    OK,上代码:

    #include  < stdio.h > #include  < unistd.h > #include  < string .h > #include  < stdlib.h > #define  BUFF_SZ 256 int  main() {     printf( " app start...\n " );          pid_t          pid;      int             pipe_fd[ 2 ];      char            buf[BUFF_SZ];      const   char      data[]  =   " hi, this is the test data " ;      int             bytes_read;      int             bytes_write;           // clear buffer, all bytes as 0     memset(buf,  0 sizeof (buf));           // creat pipe      if (pipe(pipe_fd)  <   0 )     {         printf( " [ERROR] can not create pipe\n " );         exit( 1 );     }                // fork an new process      if ( 0   ==  (pid = fork()))     {          // close the write-point of pipe in child process         close(pipe_fd[ 1 ]);                   // read bytes from read-point of pipe in child process          if ((bytes_read  =  read(pipe_fd[ 0 ], buf, BUFF_SZ))  >   0 )         {             printf( " %d bytes read from pipe : '%s'\n " , bytes_read, buf);         }                   // close read-point of pipe in child process         close(pipe_fd[ 0 ]);         exit( 0 );     }                // close read-point of pipe in parent process     close(pipe_fd[ 0 ]);           // write bytes to write-point of pipe in parent process      if ((bytes_write  =  write(pipe_fd[ 1 ], data, strlen(data))))     {         printf( " %d bytes wrote to pipe : '%s'\n " , bytes_write, data);     }           // close write-point of pipe in parent process     close(pipe_fd[ 1 ]);           // wait child process exit     waitpid(pid, NULL,  0 );          printf( " app end\n " );           return   0 ; }
    转载请注明原文地址: https://ju.6miu.com/read-1302695.html
    最新回复(0)