进程间通信一(管道)

1.什么是管道?

  管道分为无名管道和命名管道,本文中如无特殊说明均指无名管道。

  管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
A.管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
B.只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
C.单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
D.数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

2.如何创建管道?

2.1 包含头文件

#include <unistd.h>

int pipe(int pipefd[2]);

返回值:成功,返回0,否则返回-1。

参数数组包含pipe使用的两个文件的描述符:fd[0]:读端,fd[1]:写端。

3.管道数据的读写

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

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

4.实例1

#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
  pid_t pid;

  int r_num;

  int pipe_fd[2];
  char buf_r[100];
  char* p_wbuf;
  
  memset(buf_r,0,sizeof(buf_r));
  if(pipe(pipe_fd)<0)
  {
    printf("pipe create error\n");
    return -1;
  }

  if((pid=fork())==0)
  {
    printf("\n");
    close(pipe_fd[1]);
    sleep(1);
    if((r_num=read(pipe_fd[0],buf_r,100))>0)

    {
      printf("%d numbers read from pipe is:\n %s\n",r_num,buf_r);
    }

    close(pipe_fd[0]);
    exit(0);
  }

  else if(pid>0)
  {
    close(pipe_fd[0]);
    if(write(pipe_fd[1],"Hello",5)!=-1)
      printf("parent write success!\n");
    if(write(pipe_fd[1]," PIPE",5)!=-1)
      printf("parent wirte2 succes!\n");
    close(pipe_fd[1]);
    sleep(3);
    waitpid(pid,NULL,0);
    exit(0);

  }

}

4.1函数解释

  函数首先创建了一个管道,接着用fork创建了一个进程,在子进程中首先关闭管道的写端,再从管道中读取数据,接着关闭管道读端,最后子进程退出;在父进程中,首先关闭管道的读端,接着向管道中写入两次数据,接着关闭管道写端,等待子进程退出,最后退出程序;

4.2 fork()函数

  fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

4.3程序的编译、运行

[[email protected] pipe]$ls
pipe.c
[[email protected] pipe]$gcc pipe.c -o pipe
[[email protected] pipe]$ls
pipe pipe.c
[[email protected] pipe]$./pipe
parent write success!
parent wirte2 succes!

10 numbers read from pipe is:
Hello PIPE
[[email protected] pipe]$

5.实例2

这个例子是官方给的标准例子,程序首先创建一个管道,然后创建一个子进程,之后父进程关闭管道的读端,然后向管道写入命令行传入的参数,然后关闭管道的写端,父进程退出;在子进程中,首先关闭管道写端,接着读管道,数据读取完成,程序退出;

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
  int pipefd[2];
  pid_t cpid;
  char buf;

  if (argc != 2)

  {
    fprintf(stderr, "Usage: %s <string>\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  if (pipe(pipefd) == -1)

  {
    perror("pipe");
    exit(EXIT_FAILURE);
  }

  cpid = fork();
  if (cpid == -1)

  {
    perror("fork");
    exit(EXIT_FAILURE);
  }

  if (cpid == 0)

   {                   /* Child reads from pipe */
    close(pipefd[1]);         /* Close unused write end */

    while (read(pipefd[0], &buf, 1) > 0)
    write(STDOUT_FILENO, &buf, 1);

    write(STDOUT_FILENO, "\n", 1);
    close(pipefd[0]);
    _exit(EXIT_SUCCESS);

  }

  else

  {                  /* Parent writes argv[1] to pipe */
    close(pipefd[0]);       /* Close unused read end */
    write(pipefd[1], argv[1], strlen(argv[1]));
    close(pipefd[1]);        /* Reader will see EOF */
    wait(NULL);           /* Wait for child */
    exit(EXIT_SUCCESS);
  }
}

5.1程序的编译运行

[[email protected] pipe2]$ls
pipe2.c
[[email protected] pipe2]$gcc pipe2.c -o pipe2
[[email protected] pipe2]$ls
pipe2 pipe2.c
[[email protected] pipe2]$./pipe2 Hello-pipe
Hello-pipe
[[email protected] pipe2]$

时间: 2024-07-31 17:26:36

进程间通信一(管道)的相关文章

进程间通信 之 管道

一 无名管道: 特点: 具有亲缘关系的进程间通信,但不仅仅指父子进程之间哦. (1)无名管道的创建 int pipe(int pipefd 参数: pipefd  数组的首地址 返回值: 成功返回0,失败返回-1 注意: 无名管道存在内核空间,创建成功会给用户空间两个文件描述符,fd[0]:读管道 fd[1]:写管道 思考:为什么无名管道只能用于亲缘关系间进程通信? 因为只有具有亲缘关系的进程存在数据拷贝 [拷贝文件描述符] 二.有名管道 特点: (1)任意进程间通信 (2)文件系统中存在文件名

【APUE】进程间通信之管道

管道是UNIX系统IPC最古老形式,并且所有UNIX系统都提供此种通信机制.管道由下面两种局限性: 1)历史上,它们是半双工的(即数据只能在一个方向上流动) 2)它们只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后父.子进程之间就可应用该管道 管道由调用pipe函数创建: #include <unistd.h> int pipe(int filedes[2]);//若成功则返回0,出错返回-1 注意:filedes[0]为读而打开,filedes[1

Linux的进程间通信 - 管道

Linux的进程间通信 - 管道 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问问题和甄误反馈,共同进步. 微博ID:orroz 微信公众号:Linux系统技术 前言 管道是UNIX环境中历史最悠久的进程间通信方式.本文主要说明在Linux环境上如何使用管道.阅读本文可以帮你解决以下问题: 什么是管道和为什么要有管道? 管道怎么分类? 管道的实现是什么样的? 管道有多大? 管道的大小是不是可以调整?如何调整? 什

进程间通信之管道(pipe、fifo)

我们先来说说进程间通信(IPC)的一般目的,大概有数据传输.共享数据.通知事件.资源共享和进程控制等.但是我们知道,对于每一个进程来说这个进程看到属于它的一块内存资源,这块资源是它所独占的,所以进程之间的通信就会比较麻烦,原理就是需要让不同的进程间能够看到一份公共的资源.所以交换数据必须通过内核,在内核中开辟?块缓冲区,进程1把数据从?户空间 拷到内核缓冲区,进程2再从内核缓冲区把数据读?,内核提供的这种机制称为进程间通信.一般我们采用的进程间通信方式有 管道(pipe)和有名管道(FIFO)

【UNIX网络编程】进程间通信之管道

管道是最早的Unix进程间通信形式,它存在于全部的Unix实现中.关于管道,有例如以下几点须要知道: 1.它是半双工的,即数据仅仅能在一个方向上流动.虽然在某些Unix实现中管道能够是全双工的.但须要对系统进行某些设置.在Linux系统中,它是半双工的. 2.它没有名字.因此仅仅能在具有公共祖先的进程之间使用. 通经常使用在父子进程间.虽然这一点随着"有名管道FIFO"的增加得到改正了.但应该把它们看作是两种不同的进程间通信方式. 3.它由pipe函数创建,read和write函数訪问

Linux进程间通信之管道

1,进程间通信 (IPC ) Inter-Process Communication 比较好理解概念的就是进程间通信就是在不同进程之间传播或交换信息. 2,linux下IPC机制的分类:管道.信号.共享内存.消息队列.信号量.套接字 3,这篇主要说说管道:本质是文件,其他理论什么的网上已经有一大堆了,我就只写一点用法吧. 3.1 特点 1)管道是最古老的IPC,但目前很少使用     2)以文件做交互的媒介,管道分为有名管道和无名管道     3)历史上的管道通常是指半双工管道 3.2 管道:有

进程间通信之管道

管道(pipe)是进程间通信的一种方式,DEMO如下: #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define MAXLINE 4096 int main(int argc, char **argv) { int n; int f

Linux进程间通信:管道

提到进程间通信,我们需要先了解一下进程是什么: 其实在Linux下,早期的Linux为了实现多个程序之间的交替操作,出现了进程的概念.为的就是维护操作系统整个的运行逻辑.并发就是进程间的交替执行. 进程是程序的动态实例. 进程并发运行的环境中,多个进程之间存在如下竞争和合作的关系: -          进程中的资源争用(间接作用) 当并发进程竞争使用同一个资源时,它们之间就会发生冲突.为了避免冲突,当一个进程获得资源时,另一个进程必须等待.这种情况需要通过互斥机制来解决. -         

Linux IPC(Inter-Process Communication,进程间通信)之管道学习

1.标准流管道 管道操作支持文件流模式,用来创建链接还有一个进程的管道,通过函数popen和pclose popen的详细介绍在本blog:Linux 多进程学习中有具体介绍 2.无名管道(PIPE) 特点: 1)仅仅能在亲缘关系进程间通信(父子或兄弟) 2)半双工(固定的读端和固定的写端) 3)是特殊文件,能够用read,write等,在内存中 管道函数原型: #include<unistd.h> int pipe(int fds[2]); 管道在程序中用一对文件描写叙述符表示,一个是可读属

进程间通信——命名管道

概念 管道一个不足之处是没有名字,因此只能用于具有亲缘关系的进程间通信,命名管道(named pipe或FIFO)解决了这一问题. FIFO提供一个路径名与之关联,以FIFO文件的形式存储于文件系统中.文件系统中路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道. 对文件系统来说,匿名管道(管道)是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信.而命名管道是一个可见的文件,因此,他可以用于任意两个进程间进行通信,不管这两个进程是不是父子进程,也不管这两