1.IPC
进程间通信 interProcess Communication
2.管道(匿名)
1)管道的概念
- 本质:内核缓冲区
- 伪文件:不占用磁盘空间
- 特点
- 两部分:
- 读端,写端,对应两个文件描述符
- 数据写端流入,读端流出
- 操作管道的进程被销毁之后,管道自动被释放
- 管道默认是阻塞的
- 读写
- 两部分:
2)管道的原理
- 内部实现方式:队列
- 环形队列
- 特点:先进先出
- 缓冲区大小:
- 默认4K
- 大小会根据实际情况做适当调整
3)管道的局限性
- 队列:
- 数据只能读取一次,不能重复读取
- 半双工
- 匿名管道:适用于有血缘关系的进程
4)创建匿名管道 pipe
表头文件 | #include<unistd.h> |
定义函数 | int pipe(int filedes[2]); |
函数说明 | pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。 |
返回值 | 若成功则返回零,否则返回-1,错误原因存于errno中。 |
错误代码 | EMFILE 进程已用完文件描述词最大量。 ENFILE 系统已无文件描述词可用。 EFAULT 参数filedes数组地址不合法。 |
5)父子进程使用管道通信
/* 父进程借管道将字符串“hello!\n”传给子进程并显示*/
#include <unistd.h>
int main(){
int filedes[2];
char buffer[80];
pipe(filedes);
if (fork()>0) {
/* 父进程*/
char s[] = "hello!\n";
write(filedes[1], s, sizeof(s));
}
else {
/*子进程*/
read(filedes[0], buffer, 80);
printf("%s", buffer);
}
return 0;
}
hello!
6)管道读写行为
-
读操作
-
有数据
-
read(fd)-正常读,返回读出的字节数
-
-
无数据
-
写端全部关闭
-
read解除阻塞,返回0
-
相当于读文件读到尾部
-
-
没有全部关闭
-
read阻塞
-
-
-
-
写操作
-
读端全部关闭
-
管道破裂,进程被终止
-
内核给当前进程发信号SIGPIPE
-
-
-
没有全部关闭
-
缓冲区写满了
-
write阻塞
-
-
缓冲区没有满
-
write继续写
-
-
-
-
如何设置非阻塞
-
默认读写两端都阻塞
-
设置读端为非阻塞pipe(fd)
-
fcntl 变参函数
-
复制文件描述符 - dup
-
修改文件属性 - open时对应flag属性
-
-
设置方法:
-
获取原来的flags
-
int flags = fcntl(fd[0],F_GETFL);
-
-
设置新的flags
-
flags |= O_NONBLOCK;
-
fcntl(fd[0],F_SETFL,flags);
-
-
-
-
7)查看管道缓冲区的大小
- 命令
- ulimit -a
- 函数
- fpathconf
3.FIFO
1)特点
- 有名管道
- 在磁盘上有这样一个文件 ls -l -》p
- 伪文件,文件在磁盘大小为0
- 在内核中有一个对应的缓冲区
- 半双工的通信方式
2)使用场景
- 没有血缘关系的进程间通信
3)创建方式
- 命令:mkfifo 管道名
- 函数:mkfifo
表头文件 | #include<sys/types.h> #include<sys/stat.h> |
定义函数 | int mkfifo(const char * pathname,mode_t mode); |
函数说明 | mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影响 1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。 2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。 |
返回值 | 若成功则返回0,否则返回-1,错误原因存于errno中。 |
错误代码 | EACCESS 参数pathname所指定的目录路径无可执行的权限 EEXIST 参数pathname所指定的文件已存在。 ENAMETOOLONG 参数pathname的路径名称太长。 ENOENT 参数pathname包含的目录不存在 ENOSPC 文件系统的剩余空间不足 ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。 EROFS 参数pathname指定的文件存在于只读文件系统内。 |
4)fifo文件可以使用io函数进行操作
- open/close
- read/write
- 不能执行lseek操作
5)进程间通信
a.fifo文件 --- myfifo
- 两个不相干的进程A(a.c) B(b.c)
- a.c --》 read
- int fd = open("myfifo",O_RDONLY);
- read(fd,buf,sizeof(buf));
- close(fd);
- b.c --》 write
- int fd1 = open("myfifo",O_WRONLY);
- write(fd1,"hello,world",11);
- close(fd);
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <iostream>
using namespace std;
#define FIFO "./abc"
int main() {
char buffer[80];
int fd;
unlink(FIFO);
mkfifo(FIFO, 0666);
if (fork()>0) {
char s[] = "hello!\n";
fd = open(FIFO, O_WRONLY);
write(fd, s, sizeof(s));
close(fd);
}
else {
fd = open(FIFO, O_RDONLY);
read(fd, buffer, 80);
printf("%s", buffer);
close(fd);
}
return 0;
}