IPC(InterProcess Communication,进程间通信)是进程中的重要概念。Linux 进程之间常用的通信方式有:
文件:简单,低效,需要代码控制同步管道:使用简单,默认阻塞 匿名管道 pipe:只存在于内核缓冲区,只能用于有血缘关系的进程有名管道 FIFO:在文件系统中存在,可用于无血缘关系的进程信号量:使用复杂,但开销小,操作系统本身支持信号量内存映射区 mmap:进程有无血缘关系都可以本地套接字 socket:稳定可靠通过管道,可以把一个进程的输出作为另一个进程的输入。管道分为两种:
匿名管道:主要用于两个进程间有父子关系的进程间通信命名管道:主要用于没有父子关系的进程间通信通常用的管道,都是匿名管道。管道实际上是一块内核缓冲区,不占用磁盘空间,但操作方式跟文件是一样的。
在 Linux 的命令行终端中,管道是再常用不过的命令技巧了。通过管道可以把前一个命令的输出作为后一个命令的输入。在 Linux 命令中通常通过符号 | 来使用管道。
例如,查看所有的进程,然后按关键字过滤:
ps aux | grep mysql匿名管道是不能在文件系统中以任何方式看到的半双工管道,不占磁盘空间。管道的特点有:
一端只读或只写。读端、写端分别是一个文件描述符操作管道的进程退出后,管道自动释放管道默认是阻塞的半双工,数据在管道内只能单向传输匿名管道无法判断消息是否被读完,通常仅用于父进程向子进程传递数据,或子进程向父进程传递数据。此时可以在父子进程中关闭不用的读或写端。
管道是基于环形队列这个数据结构实现的,数据先进先出。默认的缓冲区大小是 4 KB,大小会自动调整。
单工:数据单向流动,例如遥控器双工:数据可以同时双向流动,例如手机半双工:数据可以双向流动,但不可同时双向流动,例如对讲机pipe() 函数用于创建匿名管道。.
函数原型:
#include <unistd.h> int pipe(int pipefd[2]);参数:返回文件描述符数组,对应管道的两端,往写端写的数据会被内核缓存起来,直到读端将数据读完。其中:
pipefd[0]:读端pipefd[1]:写端返回值:成功返回 0,否则返回-1。
示例:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { int fd[2]; int ret, pid; char buf; ret = pipe(fd); if (ret == -1) { perror("pipe error"); exit(1); } pid = fork(); if (pid == 0) { close(fd[1]); while(read(fd[0], &buf, 1) > 0) { // 两种方式都可以实现输出 printf("%c\n", buf); write(STDOUT_FILENO, &buf, 1); } close(fd[0]); } else if (pid > 0) { close(fd[0]); write(fd[1], "hello world", 12); close(fd[1]); wait(NULL); } else { perror("fork error"); exit(1); } close(fd[0]); close(fd[1]); return 0; }命名管道也叫 FIFO 文件,在文件系统中以文件名的形式存在,大小为0。匿名管道无法在无关进程之间通信,但 FIFO 可以借助文件系统中的文件,使得同一主机内的所有的进程都可以通信。
进程通过 FIFO 通信时,首先要打开管道文件,然后使用 read 、write 函数通信。
函数原型:
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);参数:
pathname:指定文件名mode:指定文件的读写权限返回值: 函数成功返回 0,否则返回-1 并设置 errno,常见 errno 有:
EACCES:pathname 所在的目录不允许执行权限EEXIST:pathname 已经存在ENOENT:目录部分不存在ENOTDIR:目录部分不一个目录EROFS:路径指向一个只读的文件系统示例: 创建两个进程,一个将文件内容读到 FIFO,另一个从 FIFO 读内容写到另一个文件。 写 FIFO 的文件示例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #define BUFSIZE 1024 int main(int argc, char *argv[]){ int ret; int datafd, fifofd; int bytes; char buffer[BUFSIZE]; const char *fifoname = "/tmp/fifo"; if (argc != 2) { printf("please input filename\n"); exit(EXIT_FAILURE); } if (access(fifoname, F_OK) < 0) { ret = mkfifo(fifoname, 0777); if (ret < 0) { perror("mkfifo error"); exit(EXIT_FAILURE); } } fifofd = open(fifoname, O_WRONLY); datafd = open(argv[1], O_RDONLY); if (fifofd < 0) { perror("open fifo error"); exit(EXIT_FAILURE); } if (datafd < 0) { perror("open file error"); exit(EXIT_FAILURE); } bytes = read(datafd, buffer, BUFSIZE); while (bytes > 0) { ret = write(fifofd, buffer, bytes); if (ret < 0) { perror("write fifo error"); exit(EXIT_FAILURE); } bytes = read(datafd, buffer, BUFSIZE); } close(fifofd); close(datafd); return 0; }读 FIFO 的文件示例:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #define BUFSIZE 1024 int main(int argc, char *argv[]) { char *fifoname = "/tmp/fifo"; int fifofd, datafd; int bytes, ret; char buffer[BUFSIZE]; if (argc != 2) { printf("please input a filename"); exit(EXIT_FAILURE); } fifofd = open(fifoname, O_RDONLY); datafd = open(argv[1], O_WRONLY); if (fifofd < 0) { perror("open fifo error"); exit(EXIT_FAILURE); } if (datafd < 0) { perror("open file error"); exit(EXIT_FAILURE); } bytes = read(fifofd, buffer, BUFSIZE); while(bytes > 0) { ret = write(datafd, buffer, bytes); if (ret < 0) { perror("write file error"); exit(EXIT_FAILURE); } bytes = read(fifofd, buffer, BUFSIZE); } close(datafd); close(fifofd); return 0; }转载于:https://www.cnblogs.com/kika/p/10851500.html
