对于管道的两端来说,管道是单向的,所以一端设置成只读,另一端设置成只写。同时两端的文件操作也分别设置成read_pipe_fops,write_pipe_fops,结构如下:
struct file_operations read_pipe_fops = {
llseek: pipe_lseek,
read: pipe_read,
write: bad_pipe_w,//pipe_write,
poll: pipe_poll,
ioctl: pipe_ioctl,
open: pipe_read_open,
release:pipe_read_release,
};
struct file_operations write_pipe_fops = {
llseek: pipe_lseek,
read: bad_pipe_r,//pipe_read,
write: pipe_write,
poll: pipe_poll,
ioctl: pipe_ioctl,
open: pipe_write_open,
release:pipe_write_release,
};
其中,bad_pipe_w()和bad_pipe_r()函数分别用来返回错误代码。是的文件只支持读或者写。
6.1怎么做到进程间通信?
管道的两端在创建之初都在同一个进程中,显然起不到通信的作用。怎样才能将管道用于进程间通信呢
1)进程A创建一个管道,创建完成时代表管道两端的两个已打开文件都在进程A中(下图所示:父进程创建管道)
2)进程A通过fork()创建出进程B,在fork()的过程中进程A大打开文件表按照原样拷贝到进程B中(下图所示:父子进程共享管道)
3)A关闭管道的读端,而B关闭进程的写端。管道的写端在进程A中,而进程的读端在进程B中,成为父子进程之间的通信管道(下图:父子管道通过管道单向通讯)。
4)进程A又通过fork()创建进程C,然后关闭其管道写端而与管道脱离关系。使得管道的写端在进程C中,读端在进程B中。成为两个兄弟进程之间的管道(如下图所示,兄弟进程之间通过管道单向通讯)、
5)进程C和B各自通过exec()执行各自的目标程序,并通过管道进行单向通信、
6.2命名管道
由于管道是一种无形,无名的文件,它就只能通过fork()的过程创建在“近亲”的进程之间,而不可能成为可以在任意两个进程之间建立通信的机制,更不可能成为一般的,通用的进程间通信模型。同时,管道机制的这种缺点本身就强烈地暗示着人们,只要用有名,有形的文件来实现管道,就能克服这种缺点。这里所谓的有名是指这样一个文件应该有文件名,使得任何进程都可以通过文件名或者路径名与这个文件挂上钩;在这里,“有形”是指文件的inode应该存在于磁盘或者其他文件系统上,使得任何进程在任意时间(不仅仅是在fork()时)都可以建立(或断开)与这个文件的联系。所以命名管道的出现时必然的。
为了实现“命名管道”,在“普通文件”,“块设备文件”,“字符设备文件”之外由设立了一种文件类型,称为“FIFO”文件。对于这种文件的访问,严格遵循先进先出的原则,而不允许有在文件内移动读写指针位置的lseek()操作。这样一来,就可以像在磁盘上建立一个文件一样地建立一个命名管道,具体可以使用mkmod命令建立:
$mkmod mypipe p
这里的参数p表示所建立的节点(也就是特殊文件)的类型为命名管道。
建立了这样的节点以后,有关进程就可以想打开一个文件一样“打开”与这个命名管道的联系。对于FIFO文件上的操作可以通过下列几个file_operations数据结构确定:
struct file_operations read_fifo_fops = {
llseek: pipe_lseek,
read: pipe_read,
write: bad_pipe_w,//pipe_write,
poll: fifo_poll,
ioctl: pipe_ioctl,
open: pipe_read_open,
release:pipe_read_release,
};
struct file_operations write_fifo_fops = {
llseek: pipe_lseek,
read: bad_pipe_r,//pipe_read,
write: pipe_write,
poll: fifo_poll,
ioctl: pipe_ioctl,
open: pipe_write_open,
release:pipe_write_release,
};