管道
管道由于传递数据只能单向传递,因此又称半双工管道,它是一种两个进程间进行单向通信的机制.
局限性:
*数据只能由一个进程流向另一个进程,若要进行全双工通信,则需建立两个管道.
*管道只能用于具有亲缘关系的进程间通信.
*管道无名字.
*管道的缓冲区大小受限制.
*管道所传递的是无格式的字节流,这就要求管道的输入和输出事先约定好数据格式.
使用管道进行通信时,两端的进程向管道读写数据是通过创建管道时,系统设置的文件描述符进行的.
管道是一个特殊的文件,这个文件只存在于内存中.在创建管道时,系统为管道分配一个页面作为数据缓冲区,进行管道通信的两个进程通过读写这个缓冲区来进行通信.
写入的数据每次添加在管道缓冲区的末尾,读数据时都是从缓冲区的头部读出数据.
管道的创建
linux下创建管道可以通过函数pipe完成,该函数如果调用成功返回0,并且数组中将包含两个新的文件描述符.如果有错误发生,则返回-1.
管道两端分别用描述符fd[0]及fd[1]来描述.
管道两端的任务固定.fd[0]为管道读端,fd[1]为管道写端.
管道是一种文件,创建成功后就可以作为一般文件来使用,因此对文件操作的I/O函数都可以用于管道,如read(),write()等.
管道的一般用法
进程在使用fork函数创建子进程前先创建一个管道,该管道用于在父子进程间通信.然后创建子进程,之后父进程关闭管道读端,子进程关闭管道写端,父进程负责向管道写数据,子进程负责读数据.也可以父进程关闭管道写端,子进程关闭管道读端.
管道的读写
从管道中读数据
要读取管道中数据的进程要关闭管道写端fd1,同时向管道写数据的进程应关闭读端fd0.(因为是用于具有亲缘关系的进程间通信,所以共享文件描述符).使用前,应及时关闭不需要的另一端,避免错误的发生.
进程在管道的读端读数据时,
1.如果管道写端不存在,则读进程认为已经读到数据的末尾,读函数返回读出的字节数为.
2.若管道写端存在,
(1)且请求读取的字节数大于PIPE_BUF,则返回管道中所有数据,
(2)如果不大于PIPE_BUF,则返回管道中现有的所有数据(管道中数据量小于请求的数据量). 或返回请求的字节数(管道中数据量大于等于请求的数据量)
向管道中写数据
如果某进程希望向管道中写入数据,那么该进程应关闭读端fd0文件描述符,同时管道另一端的进程关闭fd1.
向管道写入数据时,linux不保证写入的原子性.
>原子性:操作在任何时候都不能被任何原因打断,操作要么不做要么就一定完成.
管道缓冲区一有空闲区域,写进程就会试图向管道写入数据,若读进程不读走缓冲区的数据,则写操作一直被阻塞等待.
在写管道时,如果请求的字节数小于等于PIPE_BUF,则多个进程对同一管道的写操作不会交错进行,但如果有多个进程同时写一个管道,且某些进程要求写的字节数超过PIPE_BUF所能容纳时,则多个写操作的数据可能会交错.
>只由管道读端存在时,向管道中写入数据才有意义.否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号,如果忽略或扑捉该信号并从其处理程序返回,则write出错,错误码为EPIPE.