0. 简介
进程间通信常见方式如下:
管道
FIFO
消息队列
信号量
共享内存
UNXI域套接字
套接字(Socket)
1. 管道
管道是一种古老的IPC通信形式。它有两个特点:
- 半双工,即不能同时在两个方向上传输数据。有的系统可能支持全双工。
- 只能在父子进程间。经典的形式就是管道由父进程创建,进程fork子进程之后,就可以在父子进程之间使用了。
使用popen函数和pclose函数结合来执行系统命令,就用到了管道,它们声明如下:
FILE *popen(const char *command,const char *type);
int pclose(FILE *stream);
2. FIFO
FIFO也被称为命名管道,与管道不同的是,不相关的进程也能够进行数据交换。
涉及FIFO操作主要函数为:
int mkfifo(const char *path, mode_t mode);
而FIFO也常常有以下两个用途:
- 无需创建中间临时文件,复制输出流
- 多客户-服务进程应用中,通过FIFO作为汇聚点,传输客户进程和服务进程之间的数据
写进程代码如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#define FIFO "/tmp/fifo"
#define MAX_LEN 128
int main(void)
{
int writeFd;
char line[MAX_LEN] = {0};
if(mkfifo(FIFO,S_IRUSR|S_IWUSR) < 0 && (errno != EEXIST))
{
perror("make fifo failed:");
return -1;
}
/*关闭管道的读描述符*/
writeFd = open(FIFO,O_WRONLY,0);
/*向管道写入数据*/
write(writeFd,"www.yanbinghu.com",sizeof("www.yanbinghu.com"));
close(writeFd);
return 0;
}
它先打开一个已知的FIFO,然后从FIFO中读取数据。两个没有亲缘关系的进程可以通过FIFO进行通信。
3. 消息队列
消息队列可以认为是一个消息链表,存储在内核中,进程可以从中读写数据。与管道和FIFO不同,进程可以在没有另外一个进程等待读的情况下进行写。另外一方面,管道和FIFO一旦相关进程都关闭并退出后,里面的数据也就没有了,但是对于消息队列,一个进程往消息队列中写入数据后退出,另外一个进程仍然可以打开并读取消息。消息队列与后面介绍的UNIX域套接字相比,在速度上没有多少优势。
4. 信号量
信号量是一个计数器,它主要用在多个进程需要对共享数据进行访问的时候。考虑这一的情况,不能同时有两个进程对同一数据进行访问,那么借助信号量就可以完成这样的事情。
它的主要流程如下:
检查控制该资源的信号量
如果信号量值大于0,则资源可用,并且将其减1,表示当前已被使用
如果信号量值为0,则进程休眠直至信号量值大于0
也就是说,它实际上是提供了一个不同进程或者进程的不同线程之间访问同步的手段。
5. 共享内存
共享内存允许多个进程共享一个给定的存储区,由于它们是共享一块内存数据,因此其速度非常快。但是需要另外提供手段来保证共享内存的同步访问,例如它可以用到前面所提到的信号量来实现访问同步。
6. UNIX域套接字
UNIX域套接字和套接字很相似,但是它有更高的效率,因为它不需要执行协议处理,例如计算校验和,发送确认报文等等,它仅仅复制数据。
当然,它也只适用于同一台计算机上的进程间通信。
例如redis服务配置unixsocket启动后,通过redis-cli的-s参数就可以指定UNIX域套接字,连接到redis服务器。
$ redis-cli -s /tmp/redis.sock
redis /tmp/redis.sock>
它会比使用网络套接字的速度要快。
Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。与管道相比,Unix domain sockets 既可以使用字节流,又可以使用数据队列,而管道通信则只能使用字节流。Unix domain sockets的接口和Internet socket很像,但它不使用网络底层协议来通信。Unix domain socket 的功能是POSIX操作系统里的一种组件。
Unix domain sockets 使用系统文件的地址来作为自己的身份。它可以被系统进程引用。所以两个进程可以同时打开一个Unix domain sockets来进行通信。不过这种通信方式是发生在系统内核里而不会在网络里传播。
7. 网络套接字
这个不用多说,它利用网络进行通信,与前面所提到的通信方式不同的是,它能用于不同计算机之间的不同进程间通信。
网络套接字(英语:Network socket;又译网络套接字、网络接口、网络插槽)在计算机科学中是电脑网络中进程间资料流的端点。使用以网际协议(Internet Protocol)为通信基础的网络套接字,称为网际套接字(Internet socket)。因为网际协议的流行,现代绝大多数的网络套接字,都是属于网际套接字。
定义
系统内部接口(内部网络),接口描述符(抽象接口描述符)和接口地址之间的差别其实很细微,日常编程用的时候几乎不做区别。并且详细的网络接口有下面几种特征:
(1)本地接口地址,由本地ip地址和(包括TCP,UDP)端口号
(2)传输协议,例如TCP、UDP、raw IP协议,如果只是指定IP地址,那么TCP 53与UDP 53不是一个接口。
示例:
Socket socket = getSocket(type = "TCP")
connect(socket, address = "1.2.3.4", port = "80")
send(socket, "Hello, world!")
close(socket)
参考: