1. 进程通信的方式:
同一主机内:
1. 传统进程间通信方式:
- 管道—-无名管道 (1) 、有名管道 (2)
- 信号 (3)
2. 系统V的进程间通信方式:
- 共享内存 (4) —通信效率最高的通信方式
- 消息队列 (5) —专门应用场景
- 信号量 (6) —用于多进程间的信号量
不同主机间:
3.网络的通信 :—— socket (7)
2. 进程间通信原理(本质):

进程拥有独立的4G内容空间(3G用户空间,1G内核空间)
共享了内核空间 — 可以借助内核空间完成通信。
一、管道
1. 无名管道
1). 创建无名管道
头文件:#include <unistd.h>
语法:int pipe(int pipefd[2]);
功能: 在内核创建一条管道。
参数:
- @pipefd — 获得管道得读端和写端
pipefd[0] —读端 — 文件描述符
pipefd[1] —写端 — 文件描述符
返回值: 成功返回0,失败返回-1 && errno 被设置。
int fd[2];
int ret=pipe(fd)
if(ret<0)
{
perror("pipe fail");
return -1;
}
管道读写:
write(fd[1],buf,10);
read(fd[0],buf,10);
管道关闭:
close(fd[0]);
2). 无名管道特性
工作模式 :半双工(同一时刻只能单向传输)。
数据存储 :FIFO队列(先进先出),读走即删除。
文件属性 :特殊文件,不支持`lseek`定位。
IO操作 :使用文件IO:`/read/write/close`。
容量限制 :建议值4K,实际测试64K(65536字节)。
管道有三种工作模式:
- 单工 — 固定读端和写端,eg:广播
- 半双工 — 同一时刻只能单向传输,eg:对讲机
- 全双工 — 可以同时读和写,eg:手机
3). 管道读写规则
| 写端存在 | 读端存在时 | 管道空 → 可写 |
| 管道满 → 写阻塞 | ||
| 读端关闭时 | 继续写 → 触发SIGPIPE(管道破裂)信号,进程异常终止 | |
| 读端存在 | 写端存在时 | 管道有数据 → 读取 |
| 管道空 → 读阻塞 | ||
| 写端关闭时 | 管道有数据 → 读完数据 | |
| 管道空 → read()立即返回0,不阻塞,继续执行代码 |
注意:无名管道只能用于亲缘关系进程间通信。
2.有名管道
有名管道,可以用于任意两个进程间(亲缘和非亲缘都可以–只要用的是同一个管道)。
特性:
- 1.特殊文件
- 2.不占用磁盘空间,因为它得空间在内核(内存空间)
- 3.使用思路:1.打开 –fp / fd ;2.读/写 ;3.关闭
1). 创建有名管道
语法:int mkfifo(const char *pathname, mode_t mode);
功能: 创建管道文件。
参数:
- @pathname — 管道文件得名字
- @mode — 创建得权限,0666
返回值: 成功返回0,失败返回-1 && errno被设置 。
2). 删除管道
语法:int unlink(const char *path);
功能:删除一个管道。
返回值:成功返回0,失败返回-1且errno被设置(如果两个进程都有删管道操作,那么会失败,提示管道不存在)
3). 阻塞特性
open()时程序会阻塞,直到另一端以相对方式打开:
- A以O_RDONLY打开 → 阻塞等待B以O_WRONLY打开
- B以O_WRONLY打开 → 阻塞等待A以O_RDONLY打开
- 如果不想阻塞,以O_RDWR打开方式
二、信号通信——软中断
1.信号基础:
信号的本质是软中断,异步通信机制。

2. 信号函数
1). 注册信号处理函数——signal()
语法:sighandler_t signal(int signum, sighandler_t handler);
功能: 用来注册一个信号的处理函数,函数执行收到信号后的处理。
参数:
- @signum — 要处理的信号
- @handler — 指向信号对应的处理函数的函数指针
返回值: 成功返回上一次的处理函数的地址,失败 SIG_ERR 。
2). 信号处理函数
信号处理函数:void (*sighandler_t)(int);
参数 :@signo — 表示信号的编号。
信号处理函数可为系统宏定义的SIG_DFL,表终止处理,SIG_IGN ,表忽略信号,也可以自己定义一个函数。
可以通过SIGCHLD信号(子进程改变状态时,父进程会受到这个信号),自定义信号处理函数,实现异步回收资源处理。

3). 发信号——kill()
语法:int kill(pid_t pid,int sig);
功能:给进程发信号。
参数:
- @pid — 对应的进程pid
- @sig — 要发的信号
4). 等待信号——pause()
语法:int pause(void);
功能:阻塞等待,直到一个信号的输入。
eg:10)SIGUSR1—用户信号1,默认行为:让进程结束。
三、系统V——共享内存

共享内存是通信效率最高的进程通信方式。
1.原理:
通过同一个key值找到同一个共享内存(IPC对象)。
进程都是通过IPC对象唯一的名字(称为key)找到IPC对象,但内核是通过IP(对象的ID)来找。所以不同进程只要获得同一IP,就可以实现操作同一IPC对象,实现进程间通信。
2.函数:
1). 获得key——ftok()
头文件:#include <sys/types.h> #include <sys/ipc.h>
语法:key_t ftok(const char *pathname, int proj_id);
功能:获得key值。
参数:
- @pathname — 一个已存在的文件路径(避免".",用"/"表示当前路径)
- @proj_id — 只会使用低八位的工程id
返回值:成功返回id,失败返回-1且errno被设置。
key_t key=ftok("/",'A');
if(key<0)
{
perror("ftok fail");
return -1;
}
printf("key = %#x\\n",key);
2).申请共享内存——shmget()
头文件:#include <sys/ipc.h> #include <sys/shm.h>
语法:int shmget(key_t key, size_t size, int shmflg);
功能:申请一块指定大小的共享内存。
参数:
- @key — 获得key方式:1.IPC_PRIVATE:在亲缘间进程通信使用;2.通过ftok获得的key值:可在任意进程间使用。
- @shmflg:
IPC_CREAT|0666:对应的共享内存段空间不存在则创建,存在则返回id号。
IPC_CREAT|IPC_EXCL|0666:对应的共享内存空间不存在则创建,存在则报错,错误码为EEXIST - @size— 申请的大小,实际分配的内存空间为4K的倍数,可用大小为申请的大小。
返回值:成功返回共享内存id,失败返回-1且errno被设置。
int shmid = 0;
if((shmid=shmget(key,1024,IPC_CREAT|0666))<0)
{
perror("shmget fail");
return -1;
}
printf("id = %d\\n",shmid);
3). 共享内存映射——shmat()
语法:void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存到进程的私有地址空间。
参数:
- @shmid — 共享内存id
- @shmadder — NULL,系统自动映射到进程。
- @shmflg — 0,表示映射可以读写;SHM_RDONLY,映射后只能读。
返回值:成功返回映射所在的地址,失败返回(void*)-1且errno被设置。
注意:进程结束,映射自动撤销。
4). 撤销映射共享内存——shmdt()
语法:int shmdt(const void* shmaddr);
功能:撤销映射共享内存。
参数:
- @shmaddr — 必须是从shmdt获得的地址。
5). 删除共享内存
语法:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:对共享内存进行控制。
参数:
- @cmd — 设置为IPC_RMID,可实现对共享内存的删除。
- @buf — 共享内存的信息。
shmctl(shmid,IPC_RMID,NULL);





