Posix管道基本知识
来源:互联网 发布:淘宝客网页模板 编辑:程序博客网 时间:2024/05/18 08:04
1. 基本信息
管道是最早的IPC形式,一般可以分为管道和FIFO(命名管道)两类,使用通常的read和write进行读写。管道可以分为全双工和半双工管道。不同版本的Unix提供了不同的实现。SVR4的pipe创建的为全双工管道,而posix1标准则为半双工管道。一般是先全双工管道使用socketpair函数较为可靠。
2. pipe、popen、pclose
#include <unistd.h>int pipe(int fd[2]);该函数会返回两个文件描述符,fd[0]用来读、fd[1]用来写。
尽管管道由单个进程创建,但其一般会作为进程通信的手段。过程大致如下:
首先,一个进程创建管道后fork出一个自身的副本
接着,父进程关闭读入端,子进程关闭写入端
这样就形成了一条父进程到子进程的单向流。实际上当我们执行who | sort | lp命令时,将创建3个进程和2个管道。而如果我们需要双向数据流时,其步骤如下:
A. 创建两条管道(fd1[2] 和 fd2[2])
B. fork出自身的副本
C. 父进程关闭管道1的读和管道2的写
D. 子进程关闭管道1的写和管道2的读
#include <stdio.h>FILE *popen(const char *command, const char *type);//成功返回文件指针,失败返回NULLint pclose(FILE *stream);//成功返回shell中止状态,出错返回-1command shell命令行,函数在调用进程和命令行进程间创建一个管道
type 管道类型,type = w为写管道、type = r 为读管道
3. 命名管道(FIFO)
上面我们提到的主要是匿名管道的一些接口,其主要是针对有亲缘关系的进程通信。而命名管道可以允许无亲缘关系的进程访问同一个FIFO。
#include <sys/type.h>#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);pathname 普通Unix路径名,也是该FIFO的名字
mode 权限位
本函数已经隐含指定了O_CREAT | O_EXCL标志位,即其要么创建一个FIFO,要么返回一个EEXIST错误,如果我们不希望创建一个新的FIFO则,我们需要使用open函数。在shell环境下我们可以使用mkfifo命令创建命名管道。实际上FIFO不能打开既读又写,有且仅可以由一个。对FIFO的写操作总是将内容添加到末尾,读操作总是从开头返回数据。下面我们给出一个无亲缘关系的服务器-客户端示例子:
#define FIFO1 "/tmp/fifo.1"#define FIFO2 "/tmp/fifl.2"void server(int ,int );int main(int argc, char *argv[]){int readfd,writefd;if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))perror("can't create");if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST)){unlink(FIFO1);perror("can't cread");}readfd = open(FIFO1, O_RDONLY, 0);writefd = open(FIFO2, O_WRONLY, 0);server(readfd,writefd);}客户端:
#define FIFO1 "/tmp/fifo.1"#define FIFO2 "/tmp/fifl.2"void server(int ,int );int main(int argc, char *argv[]){int readfd,writefd;readfd = open(FIFO2, O_RDONLY, 0);writefd = open(FIFO1, O_WRONLY, 0);client(readfd,writefd);close(readfd);close(writefd);unlink(FIFO1);unlink(FIFO2);exit(0);}
4. 额外属性
A. open管道时,可以指定O_NONBLOCK;或使用fcntl指定O_NONBLOCK.
B. read时,管道中的数据小于read要求的数据时,只返回可用数据
C. write时,要写入的数据小于等于PIPE_BUF,则保证写操作是原子性的,否则不保证原子性
D. write时,如果管道为非阻塞,若写入字节大于管道可用字节,则返回EAGAIN(小于PIPE_BUF);若FIFO中有一个字节的空间,则返回写入的字节数,如果满,则返回EAGAIN(大于PIPE_BUF);
E. 如果向一个没有为读打开的管道写入,则会产生一个SIGPIPE.默认为中止进程,若忽略该信号,则write返回EPIPE.
D. read一个没有为写打开的管道时,read会返回0(文件结束符)。当面对多客户的情形时,一旦最后一个客户退出,就会返回文件结束符,我们不得不关闭描述符然后重新打开,等待下一个读打开。在设计时,我们可以再服务器进程中打开一个写管道,这样就可以保证管道的写端永远有一个以上的写打开。
5. 字节流
实际上,管道使用字节流I/O模型,其不区分记录边界,解决的方法有三个:
A. 带内特殊终止符:写操作加入换行符,读每次读一行
B. 显式长度:每个记录前冠以它的长度
C. 每次连接一个记录:以连接断开标志为记录结束标志,需要为每个记录创建连接
D. fdopen:标准IO库也能读写一个管道,我们可以通过fdopen将标准IO与pipe返回的描述符相关联,可以使用fprintf, fscanf等标准库函数(结构化读写)。
E. 我们还可以自己构建结构化的消息,每个消息一个记录,这样通过读写结构化的消息就可以了,这种方案示例如下:
#define MAXMESDATA (PIPE_BUF - 2 * sizeof(long))#define MESGHDRSIZE (sizeof(struct mymesg) - MAXMESDATA)struct mymesg{ long mesg_len; long mesg_type; char mesg_data[MAXMESDATA];};ssize_t mesg_send(int fd, struct mymesg *mptr){ return write(fd,mptr,MESGHDRSIZE+mptr->mesg_len);}ssize_t mesg_recv(int fd, struct mymesg *mptr){ size_t len; ssize_t n; if((n = read(fd,mptr,MESGHDRSIZE)) == 0) return 0; else if( n != MESGHDRSIZE) return -1; if(( len = mptr->mesg_len) > ) if((n = read(fd,mptr->mesg_data,len)) != len) return -1; return len;}
使用管道时我们需要注意两个限制:
OPEN_MAX 进程最大打开文件描述符限制,sysconf可查
PIPE_BUF 可以原子化的读写一个管道的最大数据量pathconf或fpathconf可查,和管道路径相关。
- Posix管道基本知识
- Posix信号量基本知识
- 【基本知识】重定向,出错处理,管道,时间值
- POSIX
- POSIX
- posix
- POSIX
- POSIX
- POSIX
- POSIX
- Posix
- POSIX
- POSIX
- POSIX
- POSIX
- POSIX
- POSIX
- POSIX
- 第294天(30W+5)
- 详解js里的this关键字
- (三)学习绘图API
- WP8 ApplicationBar
- AFnetworking 设置超时时间
- Posix管道基本知识
- SEO实战:长尾词排名策略抢先知
- 待飞笔记(第一天 )
- Json数据解析
- web中使用validateform验证图片,ie浏览器submit不提交
- operator is not a known binary operator swift 语法错误笔记
- BASH路径与命令搜寻顺序
- Java线程(二)-创建与启动
- [SGU390]Tickets && 数位DP