IPC(InterProcess Communication,进程间通讯)是进程中的重要概念。Linux 进程之间经常使用的通讯方式有:mysql
经过管道,能够把一个进程的输出做为另外一个进程的输入。管道分为两种:web
一般用的管道,都是匿名管道。管道其实是一块内核缓冲区,不占用磁盘空间,但操做方式跟文件是同样的。sql
在 Linux 的命令行终端中,管道是再经常使用不过的命令技巧了。经过管道能够把前一个命令的输出做为后一个命令的输入。在 Linux 命令中一般经过符号 |
来使用管道。数组
例如,查看全部的进程,而后按关键字过滤:缓存
ps aux | grep mysql
匿名管道是不能在文件系统中以任何方式看到的半双工管道,不占磁盘空间。管道的特色有:bash
匿名管道没法判断消息是否被读完,一般仅用于父进程向子进程传递数据,或子进程向父进程传递数据。此时能够在父子进程中关闭不用的读或写端。数据结构
管道是基于环形队列这个数据结构实现的,数据先进先出。默认的缓冲区大小是 4 KB,大小会自动调整。socket
- 单工:数据单向流动,例如遥控器
- 双工:数据能够同时双向流动,例如手机
- 半双工:数据能够双向流动,但不可同时双向流动,例如对讲机
pipe() 函数用于建立匿名管道。.svg
函数原型:函数
#include <unistd.h> int pipe(int pipefd[2]);
参数:返回文件描述符数组,对应管道的两端,往写端写的数据会被内核缓存起来,直到读端将数据读完。其中:
返回值:成功返回 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);
参数:
返回值:
函数成功返回 0,不然返回-1 并设置 errno,常见 errno 有:
示例:
建立两个进程,一个将文件内容读到 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; }