进程间通信(1)----管道

        进程间通信的方式有:管道、信号量、消息队列、共享内存和socket套接字
        管道、信号量、消息队列、共享内存适用于单机,即完成一台主机上的两个进程或多个进程之间的通信,socket套接字适用于网络通信,通信的进程可以运行在不同的主机上。
        无名管道:无名管道是一种半双工通信方式,数据只能单方向流动,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系通常指父子进程关系。
        有名管道:有名管道也是一种半双工通信方式,适用于无亲缘关系的进程间通信。
        信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源,因此主要作为进程间以及同一进程内不同线程之间的同步手段。
        消息队列:消息队列是消息的链表,存放在内核中并有消息队列标识符标识。消息队列克服了信号传递信息量少,管道只能承载无格式字节流以及缓冲区受限等缺点。
        共享内存:共享内存是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建但是多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。
        套接字(socket):套接字也是一种进程间通信机制,与其他进程不同的是它可以用于不同主机间的进程通信。
        本文对管道进行讨论。
        管道是一种半双工通信方式,即数据只能由一个进程流入另一个进程(其中一个写管道,一个读管道),如果要进行全双工通信,需要建立两个管道。管道分为有名管道和无名管道,有名管道适用于无亲缘关系的进程之间通信,无名管道适用于有亲缘关系的进程之间通信,这种亲缘关系通常指父子进程关系。
(1)有名管道
        有名管道:在磁盘上会存在一个管道文件标识inode,但是管道文件并不占用磁盘的block空间,数据会缓存在内存上。有名管道可以应用于一台主机上有权限访问的任意n个进程之间通信。

        例如:A进程与B进程要进行通信,A进程与B进程打开同一个管道文件,这个管道文件映射一个内存空间,A进程以只写的方式访问内存上的这个空间,B进程以只读的方式访问内存上的这个空间,这样就实现了A进程与B进程之间的通信。
1、有名管道的创建
        Linux下有两种方式创建有名管道,一是在Shell下交互地建立一个有名管道,二是在程序中使用系统函数建立有名管道。
1. shell方式下可使用mknod或mkfifo命令,使用mknod命令创建有名管道mknod namepipe
2.  创建有名管道的系统调用函数有两个:mknod和mkfifo,函数原型如下:

#include <sys/types.h>
#include <sys/stat.h>
int mknod(const char *path, mode_t mod,dev_t dev);
int mkfifo(const char *path, mode_t mod);

path:创建的有名管道的全路径名;
mod:创建的有名管道的模式,指明其存储权限;
dev:设备值,该值取决于创建文件的种类,它只在创建设备文件时才会用到;
这两个函数调用成功返回0,失败返回-1。
2、有名管道的读写
        有名管道一旦创建成功,就可以作为一般的文件来使用,对一般文件进行操作的I/O函数也适用于有名管道,如open(),read(),write(),close(),在使用有名管道时,必须先调用open()将其打开,因为有名管道是一个存在于硬盘的文件。需要注意以下几点:
1. 调用open()打开有名管道的进程可能会被阻塞,若一个进程用WRONLY打开,另一个进程用RDONLY打开,不会导致阻塞,必须有一对读写;
2. 如果所有的读端关闭,则写端也会退出,反之亦然;
3. 读写的次数没有直接关系(字节流服务);
4. 如果写端保持但并没有写数据,则读端会阻塞,如果读端保持但并没有获取数据,则写端将在管道内存写满时阻塞;
(2)无名管道
        无名管道不存在管道文件标识,其原理是父子进程共享fork之前打开的文件的描述符,仅能用于父子进程之间,无名管道的数据也缓存在内存上。
        无名管道的一般用法是:进程在使用fork函数创建子进程前先创建一个管道,该管道用于在父子进程间通信,然后创建子进程,之后父进程关闭管道的读端,子进程关闭管道的写端。父进程负责向管道写数据而子进程负责读数据,当然父进程可以关闭管道的写端而子进程关闭管道的读端,这样无名管道就可以用于父子进程间的通信。

        例如:父进程与子进程要进行通信,进程创建并打开一个无名管道,即在内存上开辟一块空间,使得该进程中有2个文件描述符,然后调用fork函数生成子进程,父进程中有两个文件描述符分别以写读的方式指向开辟的内存空间,子进程继承父进程,子进程中有两个文件描述符分别以读写的方式指向开辟的内存空间,这样就实现了父进程与子进程之间的通信。
1、无名管道的创建
        Linux下创建无名管道可以通过函数pipe完成

#include <unistd.h>
int pipe(int fd[2]);

        管道两端可分别用描述符fd[0]和fd[1]来表示,需要注意的是,管道两端的任务是固定的,一端只能用于读,用fd[0]表示,称其为管道读端,另一端只能用于写,用fd[1]表示,称其为管道写端,如果试图从管道写端读数据,或从管道读端写数据都将会出错。需要注意的是,必须在fork()之前调用pipe(),否则子进程将不会继承父进程的文件描述符,fork()之后,父子进程必须关闭一对读写,并且不能是同一个进程关闭它的读与写。
2、无名管道的读写
        无名管道一旦创建成功,就可以作为一般的文件来使用,对一般文件进行操作的I/O函数也适用于无名管道,如open(),read(),write(),close()。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值