• Linux下进程间通信(一)----概述和管道通信


    Linux下进程间通信的几种方式:

    • 管道(Pipe)和有名管道(FIFO)
    • 信号(Signal)
    • 消息队列
    • 共享内存(Shared Memory)
    • 信号量(Semaphore)
    • 套接字(Socket)

      1.管道通信

        管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,

      除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。

      2.信号

        信号是比较复杂的通信方式,用于通知接收进程有某种事件发生,除了用于进程间通信

      外,进程还可以发送信号给进程本身;Linux除了支持UNIX早期信号语义函数signal外,还支

      持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现

      可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。

        信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。

        信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用

      户空间进程发生了哪些系统事件,它可以在任何时候发给某一进程,而无须知道该进程的状态。

        如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传

      递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才传

      递给进程。 

      3.消息队列

        消息队列是消息的链接表,包括Posix消息队列System V消息队列。有足够权限的进程可以

      向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信

      息量少、管道只能承载无格式字节流,以及缓冲区大小受限等缺点。

      4.信号量/信号灯

        主要作为进程期间,以及同一进程的不同线程之间的同步手段。信号量是用来解决进程之间

      的同步与互斥问题的一种进程之间通信机制,包括一个称为信号量的变量和在该信号量下等待资

      源的进程等待队列,以及对信号量进行的两个原子操作(PV操作)。其中信号量对应于某一种资

      源,取一个非负的整型值。信号量的值是指当前可用的资源数量,若它等于0则意味着目前没有可

      用的资源。

      5.共享内存

        共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内

      存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B

      对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,

      互斥锁和信号量都可以。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读

      写内存,而不需要任何数据的复制。

      6.套接字

        更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由UNIX系统的BSD分

      支开发出来的,但现在一般可以移植到其他类UNIX系统上,Linux和System V的变种都支持套接字。

    管道通信

    特点:

    • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需建立起两个管道。
    • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。
    • 单独构成一种独立的文件系统。管道对于管道两端的进程而言,就是一个文件,但它不是普通的文

      件,不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中。

    • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加

      在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

    无名管道

    建立

    pipe函数
    相关函数 mkfifo、popen、read、write、fork
    表头文件 #include <unistd.h>
    定义函数 int pipe(int filedes[2])
    函数说明 pipe()会建立管道,并将文件描述符由参数filedes数组返回。filedes[0]为管道里的读取段filedes[1]则为管道的写入端
    返回值 若成功则返回零,否则返回-1,错误原因存于errno中
    错误代码
    • EMFILE:进程已用完文件描述符最大量
    • ENFILE:系统已无文件描述符可用
    • EFAULT:参数filedes数组地址不合法
     1 /*父进程借管道将字符串“hello!
    ”传给子进程并显示*/
     2 #include <unistd.h>
     3 int main()
     4 {
     5     int filedes[2];
     6     char buffer[80];
     7     
     8     pipe(filedes);
     9     if (fork() > 0)
    10     {
    11         /*父进程*/
    12         char s[] = "hello!
    ";
    13         write(filedes[1], s, sizeof(s));
    14     }
    15     else
    16     {
    17         /*子进程*/
    18         read(filedes[0], buffer, 80);
    19         printf("%s", buffer);
    20     }
    21 }

    读写

      管道两端可分别用描述符fd[0]和fd[1]来描述,需要注意的是,管道的两端固定了任务,即一端只能用于

    读,由描述符fd[0]表示,称其为管道读端;另一端则只能用于手写,由描述符fd[1]来表示,称其为管道写端。

    如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于

    管道,如close、read、write等等。

    从管道中读取数据:

    • 如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0。
    • 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数;如果

    请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量),

    或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。

    向管道中写入数据:

      向管道中写入数据时,Linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道

    写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

    有名管道

      有名管道和无名管道基本相同,但也有不同点:无名管道只能由父子进程使用;但是通过有名管道,不相关的

    进程也能交换数据。

    建立

    #include <sys/types.h>
    #include <sys/stat.h>
     
    int mkfifo(const char *pathname, mode_t mode);
     
    pathname: FIFO文件名
    mode:属性(同文件操作)
    一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO。

    当打开FIFO时,非阻塞标识(O_NONBLOCK)将对以后的读写产生影响:
    1、没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。如果试图读取空的FIFO,将导致进程阻塞。
    2、使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回。errno是ENXIO。

  • 相关阅读:
    socket多线程TCP和UDP
    unittest基本使用
    go语言中的文件创建,写入,读取,删除(转)
    关于mvn多模块的理解
    uniapp云开发使用云对象获取请求信息与用户信息
    Springboot2.x 使用 micaxss 实现 xss 过滤
    北大韦神透露现状:自己课讲得不太好,中期学生退课后就剩下5、6个人
    来看看一位阿里P9的年薪和资产
    埋头苦干熬到年底,还是没有被提拔!
    【运维】Linux内存占用分析的几个方法,你知道几个?
  • 原文地址:https://www.cnblogs.com/kutoli/p/7999767.html
Copyright © 2020-2023  润新知