管道基础

##管道基础

#通信分类:只写单工管道、只读单工管道、半双工管道(单向读写)、全双工管道(两个半双工管道拼接)

类型 创建/打开 关闭 读 写

单工 popen() pclose() read() write()

半双工 pipe()/open() close() read() write()

FIFO半双工 mkfifo()/open() close()/unlink() read() write()

全双工 socketpair() close() read() write()

管道通常用于进程间通信,可以用KFC买东西来比喻,通过man 7 pipe来查看管道在redhat中的官方解释。

#管道的分类

@匿名管道

特点:必须是亲缘进程之间

案例:

ps_self \\打印自身的父子进程信息

ps_other \\执行参数中的命令,并且打印参数中的命令相关的父子进程

分类:

*单工管道

操作: 管道 文件

打开 popen() fopen()

关闭 pclose() pclose()

打开管道:FILE* popen(const char* command,const char* open_mode);

command:命令行字符串

open_mode:只读"r";只写"w"

返回值:文件描述符 NULL(打开失败)

读写:

size_t fread(void* buffer,size_t size,size_t count,FILE* stream)

buffer:用于接收数据的内存地址

size:读取每个数据项的字节数

count:数据项个数

stream:输入流

返回值:出错(>count)、整数(实际读取的数据项个数)

size_t fwrite(const void* buffer,size_t size,size_t count,FILE* stream)

buffer:写入数据的内存地址

size:写入数据项的字节数

count:写入数据项的个数

stream:目标文件指针

返回值:出错(>count)、正数(实际写入的数据项个数)

关闭管道:int pclose(FILE* stream);

stream:文件描述符

返回值:失败(-1)、成功(0)

本质:

a.启动shell和命令两个进程,从命令进程中读/写文件流

b.解决exec和system无法返回输出数据问题

特点:

a.方便使用系统自带功能,并且可以执行比较复杂shell

b.默认启动两个进程,效率较低

*半双工管道

操作:

创建管道:int pipe(int filedes[2])

filedes[0] 读

filedes[1] 写

返回值:失败(-1)、成功(0)

读写

ssize_t write(int fd,const void* buf,size_t nbyte)

fd:文件描述符

buf:写入数据的内存单元

nbyte:写入文件指定的字节数

返回值:出错(-1)、正数(写入的字节数)

ssize_t read(int fd,void* buf,size_t count)

fd:文件描述符

buf:读入数据的内存单元

返回值:出错(-1)、0(无数据)、正数(读取的字节数)

控制:如果管道是空的,read()默认是阻塞

int fcntl(int fd,int cmd,long arg)

fd:文件描述符

cmd:F_GETFL(获取文件描述符状态)、F_SETFL(设置文件描述符状态)、……

arg:O_NONBLOCK(非阻塞)、O_BLOCK(阻塞)、……

fcnt(filedes,F_SETFL,O_NONBLOCK); \\把文件描述符改为非阻塞的。

关闭管道:close(filedes)

本质:文件描述符[文件流是文件描述符之上的封装。文件流通过增加缓冲区减少读写系统调用次数来提高读写效率。在进程的用户空间封装的FILE结构,以提高可移植性和效率]

*复制管道

定义:Linux内核使用三个关联的数据结构,表示打开的文件。【描述符表,文件表,v-node表】内核为每个进程创建的文件文件描述符。

分类 文件描述符 文件号

标准输入 STDIN_FILENO 0

标准输出 STDOUT_FILENO 1

标准出错信息 STDERR_FILENO 2

int dup(oldfd) \\返回值:-1(失败)、其他(新的文件描述符)

int dup2(int oldfd,int newfd) \\返回值:-1(失败)、其他(最小及尚未使用的文件描述符)

@【半双工】FIFO管道/命名管道

特点:可以是非亲缘进程之间;读写必须同时执行,否则阻塞。

案例:FIFO工具箱

操作:

创建命名管道:int mkfifo(pathname,mode)【古老方式:int mknod(const char *filename,mode_t mode | S_IFIFO,(dev_t)0);】

pathname:文件路径【文件必须不存在】

mode:模式

返回值:0(成功)、非零(失败)

打开FIFO文件:int open(const char* path,int mode)

pathname:文件路径

mode:模式【O_RDONLY(阻塞只读)、O_RDONLY|O_NONBLOCK(非阻塞只读)、O_WRONLY(阻塞只写)、O_WRONLY|O_NONBLOCK(非阻塞只写)】

返回值:-1(失败)、其他(文件描述符)

你可能感兴趣的:(管道基础)