UNPv2第四章:管道和FIFO

1.一个简单的客户服务器例子

UNPv2第四章:管道和FIFO_第1张图片

2.管道

所有式样的Unix都提供管道。它由pipe函数创建,提供单向数据流

#include<unistd.h>
int pipe(int filedes[2]);

pipe()会建立管道,并将文件描述词由参数filedes数组返回
filedes[0]为管道里的读取端
filedes[1]则为管道的写入端
若成功则返回零,否则返回-1,错误原因存于errno中

例子:
Main函数创建两个管道并fork一个子进程,客户然后作为父进程运行,服务器作为子进程运行。第一个管道用于从客户端向服务器发送路径名,第二个管道用于从服务器向客户端发送该文件的内容

3.popen和pclose

#include <stdio.h>
FILE * popen ( const char * command , const char * type );
    //返回:成功时为文件指针,出错时为NULL
int pclose ( FILE * stream );
    //返回:成功时为shell的终止状态,出错时为-1

type 参数只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。
command 参数是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用-c 标志,shell 将执行这个命令。

4.FIFO

FIFO由mkfifo函数创建

#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char * pathname,mode_t mode);
    //返回:成功为0,出错为-1

其中pathname是一个普通的Unix路径名。Mode参数指定文件权限位
Mkfifo函数已隐含指定O_CREAT|O_EXCL。也就是说,它要么创建一个新的FIFO,要么返回一个EEXIST错误
管道和FIFO的区别如下:

  1. 创建并打开一个管道只需要pipe,创建并打开一个FIFO则需要调用mkfifo再调用open
  2. 管道在将它打开着的进程中最后一个关闭它之后自动消失,FIFO的名字只有通过调用unlink才从文件系统中删除

FIFO需要额外调用的好处是:FIFO在文件系统中有一个名字,该名字允许某个进程创建一个FIFO,与它无亲缘关系的另一个进程却打开这个FIFO。对于管道而言是不可能的

5.管道和FIFO的额外属性

下面是管道或者FIFO的读出与写入的若干额外规则:

(1)如果请求读出的数据量多余管道或者FIFO的可用数据量,那么只返回可用数据量
(2)如果请求的数据字节小于等于PIPE_BUF,那么write操作是原子的。
(3)O_NONBLOCK标志的设置对于write操作的原子性没有影响——原子性完全由所请求的字节数是否小于等于PIPE_BUF决定的。然而当一个管道或FIFO设置成非阻塞时,来自wirte的返回值取决于待写的字节数以及管道或FIFO当前可用空间的大小。
    如果待写字节数小于等于PIPE_BUF:
       (i)如果空间足够则写入
       (ii)如果空间不足,那么立即返回EAGAIN
    如果待写字节数大于PIPE_BUF:
       (i)如果还有1字节空间,那么内核写入该管道或FIFO能容纳数目的数据字节,该数目同时作为来自write的返回值
       (ii)如果空间已满,那么立即返回EAGAIN
    如果写入一个没有打开着用于读的管道或者FIFO,那么内核产生SIGPIPE信号

6.字节流和消息

有时候应用希望对所传送的数据加上某种结构。当数据由变长消息构成,并且读出者必须知道这些消息的边界以判定何时已读出单个消息时,这种需求可能发生。下面三种技巧经常用于这个目的:
带内特殊终止序列:许多Unix应用程序使用换行符来分隔每个消息。写入进程给每个消息添加一个换行符,读出进程每次读出一行。
显示长度:每个记录前冠以它的长度。
每次连接一个记录:应用通过关闭与其对方的连接来指示一个记录的结束

7.管道和FIFO限制

系统加于管道和FIFO的唯一限制为
OPEN_MAX 一个进程在任意时刻打开的最大描述字数(至少16)
PIPE_BUF 可原子的写往一个管道或者FIFO的最大数据量(至少512)

你可能感兴趣的:(UNPv2第四章:管道和FIFO)