UNIX再学习 -- 进程间通信之管道
一、进程间通信概念
二、管道
1、无名管道
#include <unistd.h>
int pipe(int pipefd[2]);
返回值:若成功,返回 0;若出错,返回 -1.
(1)函数功能
(2)基于无名管道实现进程间通信的编程模型
《3》负责写数据的进程关闭无名管道对象的读端文件描述符 pipefd[0],而负责读数据的进程则关闭管道的写端文件描述符 pipefd[1]
(3)示例说明
//示例一
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>int main()
{int pipefd[2];if (pipe (pipefd) == -1){perror ("pipe");exit (EXIT_FAILURE);}pid_t pid;if((pid=fork())<0){perror("fork");}else if(pid==0){printf("这是子进程,pid=%d,",getpid());printf("父进程的pid=%d\n",getppid());if (close (pipefd[1]) == -1){perror ("close");exit (EXIT_FAILURE);}char text[20];ssize_t readed = read (pipefd[0], text, 20);if (readed == -1){perror ("read");exit (EXIT_FAILURE);}printf("%s\n", text);if (close (pipefd[0]) == -1){perror ("close");exit (EXIT_FAILURE);}}else{sleep (1);printf("这是父进程,pid=%d\n",getpid());if (close (pipefd[0]) == -1){perror ("close");exit (EXIT_FAILURE);}ssize_t written = write (pipefd[1], "hello world", 12);if (written == -1){perror ("write");exit (EXIT_FAILURE);}if (close (pipefd[1]) == -1){perror ("close");exit (EXIT_FAILURE);}}return 0;
}
输出结果:
这是子进程,pid=2799,父进程的pid=2798
这是父进程,pid=2798
hello world
//示例二
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h> int main(void){ int result,n; int fd[2]; pid_t pid; char line[256]; if(pipe(fd) < 0){ perror("pipe"); return -1; } if((pid = fork()) < 0){ perror("fork"); return -1; }else if(pid > 0){ //parent close(fd[0]); if(fd[1] != STDOUT_FILENO){ dup2(fd[1],STDOUT_FILENO); } execl("/bin/ls","ls",(char*)0); }else{ //child close(fd[1]); while((n =read(fd[0],line,256)) > 0){ if(write(STDOUT_FILENO,line,n) != n){ perror("write"); exit(-1); } } close(fd[0]); } return 0;
}
输出结果:
a.out
test.c
test.c~
(4)示例解析
(1)当读(read)一个写端已经被关闭的管道时,在所有数据都被读取后,read 返回 0,表示文件结束。
(2)如果写(write)一个读端已经被关闭的管道,则产生信号 SIGPIPE。如果忽略该信号或者捕获该信号并从其处理程序返回,则 write 返回 -1,errno 设置为 EPIPE。
在写管道(或FIFO)时,常量 PIPE_BUF 规定了内核中管道缓冲区的大小,如果对管道调用 write,而且要求写的字节数小于等于 PIPE_BUF,则此操作不会与其他进程对同一管道(或FIFO)的 write 操作交叉进行。但是,若有多个进程同时写一个管道(或FIFO),而且我们要求写的字节数超过 PIPE_BUF 字节数时,那么我们所写的数据可能会与其他进程所写的数据相互交叉。用 pathconf 或 fpathconf 函数可以确定 PIPE_BUF 的值。
(5)函数 popen 和 pclose
#include<stdio.h>
FILE *popen(const char* cmdstring, const char *type); //若成功则返回文件指针,出错则返回NULL。
int pclose(FILE *fp); //返回cmdstring的终止状态,若出错则返回-1。
《1》函数解析
《2》函数使用
fp = popen ("ls *.c", "r");
《3》示例说明
#include<stdio.h> int main(void)
{ char line[256]; FILE* fpin; int n; if((fpin = popen("/bin/ls","r")) == NULL){ perror("popen"); return -1; } while(fgets(line, 256, fpin) != NULL){ if(fputs(line,stdout) == EOF){ perror("fputs"); return -1; } } if(pclose (fpin) == -1){perror ("pclose");return -1;}return 0;
}
输出结果:
a.out
test.c
test.c~
2、有名管道
(1)有名管道简介
有名管道亦称 FIFO,是一种特殊的文件,它的路径名存在于文件系统中。通过 mkfifo 命令可以创建管道文件。
//创建管道文件
# mkfifo myfifo//在文件系统中,管道文件被显示成这样子
# ls -la myfifo
prw-r--r-- 1 root root 0 Jun 3 13:49 myfifo
# mkfifo --help
用法:mkfifo [选项]... 名称...
以指定的名称创建先进先出文件(FIFO)。长选项必须使用的参数对于短选项时也是必需使用的。-m, --mode=模式 设置权限模式(类似chmod),而不是rwxrwxrwx 减umask-Z, --context=CTX 将每个创建的目录的SELinux 安全环境设置为CTX--help 显示此帮助信息并退出--version 显示版本信息并退出
可以看到创建管道时是可以添加权限的:
创建管道
# mkfifo -m 0666 myfifo查看管道权限
# ls -la myfifo
prw-rw-rw- 1 root root 0 Jun 3 14:52 myfifo
即使是毫无亲缘关系的进程,也可以通过管道文件通信。
//在一个终端执行:
# echo 'hello,FIFO!' > myfifo //在另一个终端执行:
# cat myfifo
hello,FIFO!
管道文件在磁盘上只有 i 节点没有数据块,也不保存数据。
(2)基于有名管道实现进程间通信的逻辑模型
(3)函数 mkfifo
基于有名管道实现进程间的通信的编程模型:
下面介绍一下函数 mkfifo:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
返回值:成功返回 0,失败返回 -1.
《1》参数解析
pathname:文件路径名
《2》函数功能
《3》示例说明
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#define MYFIFO "myfifo" int main(void)
{ char buffer[256]; pid_t pid; int fd; unlink(MYFIFO); if(mkfifo(MYFIFO,0666) < 0){ perror("mkfifo"); return -1; } if((pid = fork())<0){ perror("fork"); return -1; }else if(pid > 0){ char s[] = "hello world!"; fd = open(MYFIFO,O_RDWR); write(fd,s,sizeof(s)); close(fd); }else{ fd = open(MYFIFO,O_RDONLY); read(fd,buffer,256); printf("%s\n",buffer); close(fd); exit(0); } waitpid(pid,NULL,0); return 0;
}
输出结果:
hello world!
4、FIFO用途
(2)客户进程-服务器进程应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程二者之间传递数据。
3、有名管道和无名管道区别
《2》是一个单工(半双工)的通信模式,具有固定的读写端。
《3》每次使用都需要创建管道对象。
《2》该管道是通过路径名来指出,在文件系统中是可以看到的,在建立管道后可以当做普通文件来使用读写操作。
《3》严格遵循先进先出的规则,对管道及 FIFO 的读总是从开始处返回数据,对它们的写则把数据添加到末尾。且不支持如 lseek()等文件定位操作。
# stat myfifo 文件:"myfifo"大小:0 块:0 IO 块:4096 先进先出
设备:801h/2049d Inode:2128483 硬链接:1
权限:(0666/prw-rw-rw-) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2017-06-03 14:52:53.952811041 +0800
最近更改:2017-06-03 14:52:53.952811041 +0800
最近改动:2017-06-03 14:52:53.952811041 +0800
创建时间:-
1、当使用O_NONBLOCK 旗标时,打开 FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开 FIFO 文件来读取,则写入的操作会返回 ENXIO 错误代码。
2、没有使用 O_NONBLOCK 旗标时,打开 FIFO 来读取的操作会等到其他进程打开 FIFO 文件来写入才正常返回。同样地,打开 FIFO 文件来写入的操作会等到其他进程打开 FIFO 文件来读取后才正常返回。
4、linux下shell编程之管道
ls 命令查看
# ls
sh.sh text.txt 可以可以指定查找脚本文件
# ls | grep *sh
sh.sh
UNIX再学习 -- 进程间通信之管道相关推荐
- UNIX再学习 -- 信号
终于讲到信号部分,很多比较重要的应用程序都需处理信号.第 9 章需要先了解信号机制再看,所以先跳过不讲.现在开始详解信号. 一.信号概念 信号是提供异步事件处理机制的软件中断. 这些异步事件可能来自硬 ...
- UNIX再学习 -- 进程关系
APUE 第 10 章信号讲完,回过头来看一下第 9 章的进程关系.终端登录和网络登录部分,我们只讲 Linux 系统的. 一.终端登录 我记得我们讲 root 登录设置时有提到,参看:C语言再学习 ...
- UNIX再学习 -- 标准I/O
这部分之前有所总结: 参看:C语言再学习 -- 文件 参看:C语言再学习 -- 输入/输出 参看:UNIX再学习 -- 文件描述符 对比:UNIX再学习 -- 文件I/O 一.流 文件I/O中,所有的 ...
- UNIX再学习 -- 文件描述符
在 UNIX/Linux 系统中,一切皆文件,这句话想必都有听过.对于文件的操作几乎适用于所有的设备,这也就看出了文件操作的重要性了.在C语言再学习部分有讲过标准I/O文件操作,参看:C语言再学习 - ...
- UNIX再学习 -- shell编程
UNIX环境高级编程看了三章,遇到不少重定向等shell命令.本想到Linux时再讲,看来有必要提前了.之前有看过一本<嵌入式Linux软硬件开发详解>这本书里有简单介绍了一部分shell ...
- UNIX再学习 -- 记录锁
APUE第 3 章,参看:UNIX再学习 -- 文件I/O fcntl 函数它的记录锁功能我们当时没讲.接下来就详细说明下. 一.读写冲突 1.如果两个或两个以上的进程同时向一个文件的某个特定的区域 ...
- UNIX再学习 -- 守护进程(转)
参看:守护进程 一.什么是守护进程 守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程.它是一个生存期较长的进程,通常独立于控制 ...
- UNIX再学习 -- 线程
终于要讲到线程部分,线程和进程让人够头痛的内容. 一.线程概念 老样子,我们还是按我们讲进程时的方式说起,参看:UNIX再学习 -- 进程环境 首先需要了解下,什么是线程. Linux 下的线程,可能 ...
- UNIX再学习 -- 函数abort
abort 函数之前有讲过的,参看:C语言再学习 -- 关键字return和exit ()函数 然后我们在讲 8 中进程终止时,也说过.参看:UNIX再学习 -- exit 和 wait 系列函数 下 ...
最新文章
- 中国大学生源质量排行榜150强
- bootstrap轮播,播放到最后一张图片的时候,就不正确了。
- Python学习笔记-day1(while流程控制)
- 【收藏】CMD命令提示符窗口中的快捷键、小技巧和常用命令
- ios 请求头设置token_HTTP中的OPTIONS请求
- php 电压 异常,tv断线警告是什么原因
- (源码)智能优化算法—藤壶交配优化算法(Barnacles Mating Optimizer,BMO)
- MACD神器 通达信指标公式 副图 源码 无加密 无未来
- 大学c语言程序中if语句,浅谈C语言中if语句
- 严蔚敏《数据结构》——二叉树
- iOS 9 spotlight搜索 3DTouch
- 为什么Java程序员工资高?
- oneDNS解决google等登陆问题
- 2019迅雷校园招聘!后端工程师岗位两次技术面题目总结和解析
- 《SQL基础》04. SQL-DQL
- ppt扇形图怎么显示数据_PPT里的扇形图/饼图怎么做才更有创意?
- VMware Workstation虚拟机显示屏幕太小问题解决方法
- 服务器阵列状态显示verify,VerifyServerName 协议选项 [VERIFY]
- 视频标准 - CCIR601,CCIR656
- Modbus通讯协议从一窍不通到原来如此
热门文章
- bootstrap-datetimepicker bootstrap-datepicker bootstrap-timepicker 时间插件
- PYTHON 函数的返回值
- 时光已荏苒,我还怎么让你遇见最美年华里的我
- 【.NET基础】--委托、事件、线程(2)
- Oracle9在Windows7下的安装
- Sql Server通用分页存储过程
- Pig安装与配置教程
- VS.Net 2005 Beta2连接Team Foundation Server的问题
- 吴恩达 coursera AI 专项五第一课(上)总结+作业答案
- IP地址,子网掩码、默认网关,DNS服务器是什么意思