进 程 间 通 信
进程间通信:三大类
1、古老的通信方式
无名管道
有名管道
信号 ====》唯一的异步通信方式
2、systemV IPC 对象
消息队列
共享内存 ===》效率最高的通信方式
信号量集
3、BSD socket 套接字
域内套接字 ==》单机进程间通信
网络套接字 ==》不同主机上的进程间通信
古老的通信方式:
1、管道 ==》无名管道 有名管道
无名管道 ==》pipe
1、特性
只能用于具有亲缘关系的进程间使用。
半双工的通信模式,有固定的读写端。
属于特殊的设备文件,只能用文件IO读写。
该类型的文件不支持定位操作。
2、使用流程
创建管道===》打开管道 ===》读写管道 ==》关闭管道
pipe() read()/write() close()
头文件: #include <unistd.h>
原型: int pipe(int fd[2]);
功能:该函数可以创建一个无名管道,
并且自动打开该管道。
参数: fd[2] 管道的读写端,有如下默认约定
fd[0] 固定的读端
fg[1] 固定的写端
返回值:成功 0
失败 -1;
读: read
写: write()
关闭: close()
有名管道 ===>fifo ===>在无名管道基础之上增加了一个文件名称
方便在不同进程间使用。
操作流程:
创建有名管道 ===》打开管道 ===》读写管道 ==》关闭管道 ===》卸载管道。
mkfifo open read/write close unlink
1、创建有名管道 ==》mkfifo
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:在指定的pathname路径下创建一个权限为mode的有名管道。
参数:pathname 要创建的有名管道的路径+管道名称
mode 要创建的管道文件权限。
返回值:成功 0
失败 -1;
***** 注意:
所有的管道都是设备文件,同时该设备文件有固定的读写端。
open();的参数2 不能是 O_RDWR,只能是O_RDONLY 或者 O_WRONLY 之一
#include <unistd.h>
int unlink(const char *pathname);
功能:通过该函数可以完成指定的有名管道卸载。文件会被删除。
参数:pathname 要卸载的管道
返回值:成功 0
失败 -1;
注意:unlink函数一般用于最后管道没有人使用的时候卸载用。
一般为了有名管道的配合使用。管道的创建工作可以独立执行
或者在读端启动的时候首先创建。
练习:
1、从a.out程序中读取指定文件内容通过有名管道发送到b.out
并从 b.out 中打印输出。
2、测试有名管道能否在fork之后的父子进程间使用。
注意:一般在项目中需要有一个有名管道的维护工具,
可以动态的手工创建并删除管道.比如:
fifo_tool 名称
功能: fifo_tool -A abc ===>在当前路径下新建一个名称为
abc 的有名管道
fifo_tool -D abc ===》删除当前路径下名称为abc的管道。
信号通信:====》传递的是信号 ,而不是数据.
通信框架: 发送端进程 ===》信号 ===》接收端进程
1、发送端进程 ===》函数: kill() raise() alarm () pause()
#include <sys/types.h>
#include <signal.h>
原型:int kill(pid_t pid, int sig);
功能: 通过该函数可以给指定的pid进程发送sig编号的信号。
参数: pid 要接受信号的进程pid号
sig 要接受的信号。
返回值:成功 0
失败 -1;
原型: int raise(int sig);
功能: 进程自身给自己发送一个sig信号。
参数: sig 发给自己的信号编号
返回值:成功 0
失败 -1;
头文件 #include <unistd.h>
原型: unsigned int alarm(unsigned int seconds);
功能:定时由OS给当前进程发送一个定时信号SIGALRM
默认该信号会杀死进程。
参数:seconds 程序从当前函数开始后seconds秒后会
收到来自OS的SIGALRM信号。
返回值:成功 0
失败 -1;
原型:int pause(void);
功能:使当前运行的进程暂停。
返回值:成功 0
失败 -1;
2、信号 ===》kill -l 中前32个不稳定信号。
3、接受端进程 ===》进程收到信号的处理过程:
每个进程对信号有三种处理方式:
1、默认处理
2、忽略处理
3、自定义处理
信号的注册函数: ==》signal 函数
原型:
void (*signal(int signum,void (*handler)(int)))(int);
===>void (*xxx)(int aa);===>函数指针
xxx == signal(int signum,void(*handler)(int));
===>typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal(int signum,fun); ===>信号注册函数
其中:signum 表示要处理的信号编号
fun 表示信号的处理方式:
如果fun == SIG_IGN ===>表示忽略处理方式
SIG_DFL ===>表示默认处理方式
函数地址 ===》自定义函数‘
重要:在所有的信号中9 号的SIGKILL 和 19 号的 SIGSTOP
信号不能被忽略。同时也不能被修改。
特殊:10 SIGUSR1
12 SIGUSR2
以上两个信号在所有32个信号中是唯一的两个没有具体
含义的临时信号,预留给程序员编程使用。
练习题:
编写信号处理程序,当收到10号和12号信号的时候启动不同的程序。
其他信号都按默认处理流程。