Linux进程间通讯(IPC)------匿名管道
2016-07-16 14:33
435 查看
当从一个管道中读取数据时,除非一端写入数据或写端关闭,否则会处于阻塞状态。
管道是单传输的,只能一端用于写,一端用于读,即是半双工的。
管道只能在具有相同祖先的进程间进行通讯。
当写入的数据小于PIPE_BUF字节时,那么写入操作是原子性的(就是要么全部数据连续写入,要么一个字节都没有写入)。这样可以确保多个进行写一个管道时,出现数据混乱问题。
管道容量有限制。当写入的数据超过容量时,写入操作会阻塞,直到另一端读出一些数据,当写完所有数据才能返回。因此为了避免阻塞,只能加快读的速度。
管道的读和写默认是阻的态,可以使用fcntl函数将管道的读写操作设为非阻塞状态。
对于读和写关闭时造成的影响
如果所有的读描述符都关闭情况下,进行write操作,将返回SIGPIPE信号
如果所有的写描述都关闭情况下,进行read操作,将返回0
对于read读取缓冲区为空,阻塞和非阻塞的情况
阻塞:read读取的缓存区为空,会阻塞read操作,知道有数据写入
非阻塞:read操作会立即返回-1,errno会返回EAGIN.
对write写缓存区满时,阻塞和非阻塞的情况
阻塞:write操作将阻塞,直到有程序将缓冲区的数据取走,write写入完所有数据。
非阻塞:write操作会立即返回-1,errno会返回EAGIN。
int pipe(int filedes[2]);
说明:返回值为int类型,0表示创建成功,-1表示创建失败。参数为2个文件描述符,fd[0]表示读描述符,fd[1]表示写描述符。
2.dup和dup2函数
可以使用dup和dup2函数复制描述符、
int dup(int oldfd);
说明:该函数用于复制oldfd描述符,返回一个新的最小的描述符。
int dup(int oldfd, int newfd);
说明:该函数用oldfd描述符,覆盖newfd描述符。
3.popen函数
FILE *popen(const char *command, const char* mode):
int pclose(FILE *stream);
说明: popen函数创建一个子进程才执行shell,而shell又创建一个子进程来执行command。
功能:该函数用于和shell命令通讯。
注意:popen使用的是块缓存,因此,一般调用进程向管道写入数据,stdio库不会立即将数据传递给另一端,除非手动调用fflush和fclose。因此对于从管道中读数据,如果对端正在操作stdio,那么命令进程写的数据不会立即传送,这种对于调用进程没有办法立即读取数据。
输出结果如下:
匿名管道的特点
数据是字节流。当从一个管道中读取数据时,除非一端写入数据或写端关闭,否则会处于阻塞状态。
管道是单传输的,只能一端用于写,一端用于读,即是半双工的。
管道只能在具有相同祖先的进程间进行通讯。
当写入的数据小于PIPE_BUF字节时,那么写入操作是原子性的(就是要么全部数据连续写入,要么一个字节都没有写入)。这样可以确保多个进行写一个管道时,出现数据混乱问题。
管道容量有限制。当写入的数据超过容量时,写入操作会阻塞,直到另一端读出一些数据,当写完所有数据才能返回。因此为了避免阻塞,只能加快读的速度。
管道的读和写默认是阻的态,可以使用fcntl函数将管道的读写操作设为非阻塞状态。
对于读和写关闭时造成的影响
如果所有的读描述符都关闭情况下,进行write操作,将返回SIGPIPE信号
如果所有的写描述都关闭情况下,进行read操作,将返回0
对于read读取缓冲区为空,阻塞和非阻塞的情况
阻塞:read读取的缓存区为空,会阻塞read操作,知道有数据写入
非阻塞:read操作会立即返回-1,errno会返回EAGIN.
对write写缓存区满时,阻塞和非阻塞的情况
阻塞:write操作将阻塞,直到有程序将缓冲区的数据取走,write写入完所有数据。
非阻塞:write操作会立即返回-1,errno会返回EAGIN。
匿名管道相关函数
1.创建管道,函数原型如下:int pipe(int filedes[2]);
说明:返回值为int类型,0表示创建成功,-1表示创建失败。参数为2个文件描述符,fd[0]表示读描述符,fd[1]表示写描述符。
2.dup和dup2函数
可以使用dup和dup2函数复制描述符、
int dup(int oldfd);
说明:该函数用于复制oldfd描述符,返回一个新的最小的描述符。
int dup(int oldfd, int newfd);
说明:该函数用oldfd描述符,覆盖newfd描述符。
3.popen函数
FILE *popen(const char *command, const char* mode):
int pclose(FILE *stream);
说明: popen函数创建一个子进程才执行shell,而shell又创建一个子进程来执行command。
功能:该函数用于和shell命令通讯。
注意:popen使用的是块缓存,因此,一般调用进程向管道写入数据,stdio库不会立即将数据传递给另一端,除非手动调用fflush和fclose。因此对于从管道中读数据,如果对端正在操作stdio,那么命令进程写的数据不会立即传送,这种对于调用进程没有办法立即读取数据。
例子
一个父子进程通过匿名管道进行通讯的例子。#include <stdio.h> #include <unistd.h> int main(int argc, char* argv[]) { int fd[2]; char buffer[1024] = {0}; char str[] = "Hello world!"; int ret = pipe(fd); if(ret ==-1) { printf("创建管道失败\n"); return -1; } pid_t pid = fork(); switch(pid) { case 0: close(fd[1]); read(fd[0], buffer, sizeof(buffer)); printf("子进程接收到数据: %s\n", buffer); break; case -1: printf("创建进程失败\n"); break; default: close(fd[0]); write(fd[1], str, strlen(str)); sleep(5);//等待子进程先于父进程结束 break; } return 0; }
输出结果如下:
相关文章推荐
- 如何隐藏你的 Linux 的命令行历史
- Linux蓝牙系统(3) Linux 命令
- CentOS7安装iptables防火墙
- Linux蓝牙系统(3) Linux 命令
- linux使用小技巧
- mysql安装在centos7报错ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
- windows系统使用Tera Term连接虚拟机(VMware Workstation) 中的Linux(CentOS)
- 怎样在Linux中使用蓝牙_百度知道
- Linux基础之磁盘挂载
- Centos7环境安装mysql5.7.13
- 【转载】Linux中socket 错误编码表 errno
- LINUX中的rfcomm命令工具的使用
- TFTP、NFS、FTP三种文件传送协议(附linux协议配置)
- vim与系统粘贴板交互
- 多线程与多进程的相关概念
- 【linux c】c语言变量_学习笔记_007
- Linux C 字符串函数的总结
- centos6环境下搭建irc服务器
- 使程序的cpu占用率呈现正弦曲线
- Linux(Ubuntu)下如何安装JDK