进程间通信的方式:
管道:匿名管道和有名管道信号 - 系统开销小共享映射区 - 有无血缘关系的进程间通信都可以本地套接字 - 稳定IPC(InterProcess Communication):进程间通信
1.1管道的概念:管道是内核缓冲区,可以叫做伪文件(不占用磁盘文件) (1)管道的特点: ①管道有读端和写端。数据从写端流入,读端流出。读端和写端是两个文件描述符。 ②含有管道的进程结束后,管道被释放 ③管道默认是阻塞的。数据必须读端流入,写端流出
(1)内部实现方式:队列(环形队列),先进先出。 (2)缓冲区大小:默认为4k,大小会根据实际情况做适当的调整
(1)数据只能读取一次,不能重复使用,数据传输方向是单向的(半双工)
单工:遥控器 半双工:数据传输的方向是单向的,对讲机 双工:数据时双向流动的,电话
(2)匿名管道:只适用于由血缘关系的进程间通信
函数:int pipe(int pipefd[2]);
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <sys/stat.h> int main() { int fd[2]; int ret = pipe(fd); if(ret == -1){ perror("pipe"); exit(1); } printf("pipe[0] = %d\n", fd[0]); printf("pipe[1] = %d\n", fd[1]); close(fd[0]); close(fd[1]); return 0; }单个进程也能使用管道完成通信,平时没有这个必要
例:父进程将数据写入管道,子进程从管道中读取数据
/* 实现 ps aux | gerp "bash" */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <sys/stat.h> int main() { int fd[2]; int ret = pipe(fd); if(ret == -1){ perror("pipe"); exit(1); } pid_t pid = fork(); if(pid == -1){ perror("fork"); exit(1); } //父进程 ps aux //子进程 grep "bush" if(pid > 0){ //写管道操作,关闭读端 close(fd[0]); //重定向,STDOUT -> 管道的写端 dup2(fd[1], STDOUT_FILENO); //执行ps aux execlp("ps", "ps", "aux", NULL); perror("execlp"); exit(1); } else if(pid == 0){ close(fd[1]); dup2(fd[0], STDIN_FILENO); execlp("grep", "grep", "bash", "--color=auto", NULL); perror("execlp"); exit(1); } close(fd[0]); close(fd[1]); return 0; }注意事项: 父进程写数据 – 关闭写端 子进程读数据 – 关闭读端 因为管道是阻塞的
程序中的重定向: 父进程中 – dup2(fd[1], STDOUT_FILENO); //STDOUT_FILENO跟随 fd[1] 子进程中 – dup2(fd[0], STDIN_FILENO); //STDIN_FILENO跟随 fd[0]
(1)管道中有数据:
read(fd) - 正常读数据,返回读出的字符数(2)管道中无数据:
写端全部关闭:read解除阻塞,返回0,相当于读文件时读到了尾部没有全部关闭:read阻塞(1)读端全部关闭
管道破裂,进程被终止:内核给当前进程发信号SIGPIPE(13号信号)(2)读端没有被全部关闭
缓冲区写满:write阻塞缓冲区没满:write继续写(3)设置管道为非阻塞
获取原来的flags:int flag = fcntl(fd[0].F_GETFL);设置新的flags:flag |= O_NONBLOCK; //flags = flags | O_NONBLOCK;fcntl(fd[0], F_SETFL, flags);1.命令查看:ulimit -a 2.函数:
#include <unistd.h> long fpathconf(int fd, int name); long pathconf(const char *path, int name);1.使用场景:没有血缘关系的进程间通信 2.创建方式:
命令:mkfifo 管道名函数:mkfifo #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);参数: ①pathname:fifo文件名 ②mode:fifo文件的打开方式 例:该进程以只读的方式打开 myfifo
int fd = open("myfifo", O_RDONLY);现有两个进程a,b属于不同的进程组。 a进程进行读操作,b进程进行写操作 a.c —> read
int fd = open("myfifo", O_RDONLY); read(fd, buf, sizeof(buf); close(fd);b.c —>read
int fd1 = open("myfifo", O_WRONLY); write(fd1, "hello,world", 11); close(fd1);