进程间的通信——管道篇

原创 2018年04月15日 12:51:06

进程间的通信——消息队列https://blog.csdn.net/q496958148/article/details/79951727
进程间的通信——共享内存https://blog.csdn.net/q496958148/article/details/79953349
进程间的通信——信号量https://blog.csdn.net/q496958148/article/details/79977093

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间必须互相通话。IPC接口就提供了这种可能性。
通常进程间通信有以下几种:

  1. 管道
  2. 消息队列
  3. 共享内存
  4. 信号量

管道

  • 管道是Unix中比较老的进程间通信的方式
  • 我们把从一个进程链接到另一个进程的数据流称为“管道”
    这里写图片描述

匿名管道:

//功能————创建匿名管道
int pipe(int pipefd[2]);
//fd:文件描述符数组,pipefd[0]代表读端,pipefd[1]代表写端
//返回值0代表成功,失败返回错误码

实例:

//实现目的:从键盘读取数据,写入管道,再从管道读取数据,写到显示器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
    int pipefd[2];
    char buf[256];
    int len;

    if(pipe(pipefd) != 0)
    {
        perror("pipe");
        exit(1);
    }
    while(fgets(buf,256,stdin))
    {
        len = strlen(buf);
        if(write(pipefd[1],buf,len) != len)
        {
            perror("write");
            break;
        }
        memset(buf,0x00,sizeof(buf));
        if((len = read(pipefd[0],buf,256)) == -1)
        {
            perror("open");
            break;
        }
        if(write(1,buf,len) != len)
        {
            perror("write");
            break;
        }
    }
}

这里写图片描述

上述实例是基于pipe函数创建的管道,而我们也可以基于“fork”函数创建子进程来进行管道实现。

操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同。

通过上述描述,我们可以知道如如所示的演示:
这里写图片描述
实例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
    int pipefd[2];
    char buf[256] = "hello,i am a man!\n";
    int len;
    char arr[256];

    if(pipe(pipefd) != 0)
    {
        perror("pipe");
        exit(1);
    }
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return -1;
    }
    else if(id == 0)
    {
        close(pipefd[0]);
        if(write(pipefd[1],buf,strlen(buf)) < 0)
        {
            perror("write");
            return -1;
        }
        close(pipefd[1]);
    }
    else
    {
        close(pipefd[1]);
        if(read(pipefd[0],arr,strlen(buf)) < 0)
        {
            perror("read");
            return -1;
        }
        close(pipefd[0]);
        printf("%s",arr);
    }
    return 0;
}

这里写图片描述

管道读写规则:

  • 当没有数据可读时
    O_NONBLOCK disabke:read调用堵塞,及进程暂停执行,直到有数据来时再读
    O_NONBLOCK enable:read调用返回-1,errno为EAGAIN
  • 当管道满时
    O_NONBLOCK disabke:write调用堵塞,直到有进程读取数据
    O_NONBLOCK enable:write调用返回-1,errno为EAGAIN
  • 如果所有的管道写端对应的文件描述符关闭,read返回0
  • 如果所有的管道读端对应的文件描述符关闭,write操作会产生SIGPIPE信号,使得进程退出
  • 当要写入的数据大小小于PIPE_MAX时,Linux将保证写入的原子性
  • 当要写入的数据大小大于PIPE_MAX时,Linux将不保证写入的原子性

管道特点:

  • 只能用于具有共同祖先(因为共同祖先代码相同,数据写实拷贝)之间的通信,通常进程fork创建子进程用来通信
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程
  • 一般而言,内核会对管道操作进行同步和互斥
  • 管道是半双工的,数据只能单向流动;而需要双向通信时则需要俩个管道
    这里写图片描述

命名管道:
- 管道的实现有个限制:必须具有许愿关系的进程通信
- 如果我们想在不相关的进程间通信,我们就得使用FIFO文件来做这项工作,它被成为“命名管道
- 命名管道是一种特殊类型的文件

创建命名管道:

  1. 可以在命令行上创建
    [XX]# mkfifo filename
  2. 也可以在程序内创建
    int mkfifo(const char *filename,mode_t mode);

    实例:

fifo.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main()
{
    umask(0);
    if(mkfifo("fifoname",0644) < 0)
    {
        perror("mkfifo");
        return-1;
    }
    int infd = open("fifoname",O_RDONLY);
    if(infd < 0)
    {
        perror("open");
        return -1;
    }
    char buf[256];
    while(1)
    {
        buf[0] = 0;
        ssize_t s = read(infd,buf,sizeof(buf)-1);
        if(s > 0)
        {
            buf[s-1] = 0;
            printf("xiaoming:%s\n",buf);
        }
        else if(s == 0)
        {
            printf("xiaoming quit.\n");
            break;
        }
        else
        {
            perror("read");
            return -1;
        }
    }
    close(infd);
    return 0;
}

1fifo.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main()
{
    int outfd = open("fifoname",O_WRONLY);
    if(outfd < 0)
    {
        perror("open");
        return -1;
    }
    char buf[256];
    while(1)
    {
        buf[0] = 0;
        printf("pleas enter:");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf));
        if(s > 0)
        {
            buf[s] = 0;
            write(outfd,buf,strlen(buf));
        }
        else
        {
            perror("read");
            return -1;
        }
    }
    close(outfd);
    return 0;
}

Makefile:

.PHONY:all
all:fifo 1fifo


fifo:fifo.c
    gcc $^ -o $@;
1fifo:1fifo.c
    gcc $^ -o $@;

.PHONY:clean
clean:
    rm -f fifo 1fifo

效果图:
这里写图片描述

命名管道和匿名管道的区别:

  • 匿名管道由pipe函数创建并打开
  • 命名管道是由mkfifo函数创建,用open打开的
  • FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在于他们创建和打开的方式不同,一旦创建并打开了,他们具有相同的语义

命名管道的打开规则:

  • 如果打开操作是为读操作而打开的FIFO
    1>O_NONBLOCK disable:阻塞直到有相应进程为写操作而打开FIFO
    2>O_NONBLOCK enable:立刻返回成功
  • 如果打开操作是为写操作而打开的FIFO
    1>O_NONBLOCK disable:阻塞直到有相应进程为读操作而打开FIFO
    2>O_NONBLOCK enable:立即返回失败,错误码为ENXIO

进程间的通信方式——pipe(管道)

详解进程间通信方式———管道;管道是如何实现进程间通信的;以及管道读取数据的四种方式,以及管道容量的大小。...
  • skyroben
  • skyroben
  • 2017-05-10 00:43:13
  • 7091

进程间通信之管道篇

何为进程间通信 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都是看不到的。所以进程之间如果要交换数据就必须通过内核。 在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核...
  • qq_33724710
  • qq_33724710
  • 2016-08-28 14:22:55
  • 806

【C语言】【unix c】如何使用管道实现两个进程间的通信

【C语言】【unix c】如何使用管道实现两个进程间的通信
  • weixin_38239856
  • weixin_38239856
  • 2017-08-31 22:36:07
  • 230

进程间的通信(二):命名管道 和 油槽

我们接着简绍2种进程间通信的方法:3.命名管道:命名管道可以再2个任意进程间通信(包括网络上的2个不同主机之上的进程) 他们建立了如客户机/服务器的连接创建命名通道的机器为服务器 连接命名通道的机器为...
  • Saint_
  • Saint_
  • 2009-07-15 21:15:00
  • 2147

共享内存,管道,socket等进程间通信方式的优缺点

进程间通信的方式有很多,常见的有信号,信号量,消息队列,管道,共享内存,和socket等,这里我们主要讨论管道,共享内存,和socket,其他的比较简单只做简单的介绍。 信号:信号主要用于通知某个进程...
  • D_Guco
  • D_Guco
  • 2016-12-08 21:14:01
  • 7777

4种进程间通信方式详解

进程间通信有4种方式,以下从简单到复杂的方式出场: 1.管道(pipe)     管道是一种具有两个端点的通信通道,一个管道实际上就是只存在在内存中的文件,对这个文件操作需要两个已经打开文件进行,...
  • u014673901
  • u014673901
  • 2016-04-07 21:09:27
  • 17094

VB进程间通讯-----使用匿名管道原代码

Option Explicit Private Declare Function CreatePipe Lib "kernel32" (phReadPipe...
  • SilenceNet
  • SilenceNet
  • 2010-04-16 18:13:00
  • 2914

进程间通信系列 之 消息队列应用实例

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间...
  • iamonlyme
  • iamonlyme
  • 2013-11-13 08:33:19
  • 1970

uc笔记09---进程通信,管道,进程间通信,共享内存,消息队列,信号量,IPC 命令

1.    基本概念     何为进程间通信:     进程间通信 (Interprocess Communication, IPC) 是指两个,     或多个进程之间进行数据交换的过程。   ...
  • wolfsun3
  • wolfsun3
  • 2015-09-30 17:04:05
  • 538

进程间通信-管道(PIPE)和有名管道(FIFO)

前面我们学习了一下进程,我们知道多,进程间的地址空间相对独立。进程与进程间不能像线程间通过全局变量通信。 如果想进程间通信,就需要其他机制。          常用的进程间通信方式有这...
  • w616589292
  • w616589292
  • 2016-03-22 18:52:34
  • 2750
收藏助手
不良信息举报
您举报文章:进程间的通信——管道篇
举报原因:
原因补充:

(最多只允许输入30个字)