你好,游客 登录 注册 搜索
背景:
阅读新闻

Linux编程---进程通信

[日期:2014-06-17] 来源:Linux社区  作者:meiboyu [字体: ]

Linux的通信方式主要有分类有下面几种:
 
-匿名管道和FIFO有名管道
 
-消息队列,信号量和共享存储
 
-套接字
 
.对于套接字的进程通信,我就留在套接字的文章中再写了.
 
一.管道

管道是最古老的进程通信机制了.提供进程间的单向通信.

1.创建管道

int pipe(int fdes[2]);

实际上管道通过参数返回读和写的两个文件描述符.相当于是打开了两个文件吧.但是这个文件是特殊的pipe文件.fdes[0]表示的是输入,fdes[2]表示的是输出.注意,这个函数只创建一个文件,而不是创建两个文件一个用来读,一个用来写.

管道创建调用成功,那么就返回0,否则返回-1,并设置errno错误条件.

如果向写文件描述符进行读,那么会生成一个SIGPIPE信号,并且当信号被阻塞是将以EPIPE错误失败.管道文件不允许文件定位,读和写操作都是顺序的,读从文件的开始处读,写则写至文件尾.

这么看似乎好像没有和别的进程关联起来.实际上,管道单独使用的话只是创建了两个文件而已,想要使用管道还得使用fork,exec,dup等函数来创建一个进程才能使用.

简答来说,对于创建的进程来说,其读写的文件是相反的.并且对于管道来说,其方向只能是单向的,所以如果你创建了新进程,两个进程至少要关闭一个文件描述符.
 
 
2.popen和pclose函数
 
这两个函数是C标准库中的两个函数.并且创建的方式也比系统调用方便.
 
FILE *popen(const char *command,const char *mode);
 
int pclose(FILE * stream);
 
第一个函数通过第一个参数,解析其命令建立一个新进程.过程就是先建立一个管道,然后派生一个子进程,调用exec启动一个shell程序执行command给出的命令.并立即返回一个管道对应的流指针.
 
mode的方式只能是”r”和”w”两种方式之一,但是不能两个一起,所以这和一般的文件模式是不同的.
 
这么来看,这个函数就比用上面的pipe系统调用方便得多.封装了包括fork,exec,dup等一系列调用~当然,这个函数相对自己调用pipe+fork+exec+close来说效率就要差一些了.
 
管道IO的原子性
 
实际上管道就是一片内存缓冲区.(我记得原来学的时候创建一个管道,然后在图形界面下把管道文件给删了,但是管道仍然正常使用).所以如果写入管道的数据块大小超过这片缓冲区的大小时,内核就要分几次写入了.如果是分批写的话,那么就很可能造成混乱了.试想如果A进程需要分3次写,在写完第二次的时候时间片到了,切换到另外一个进程也要往这个管道写内容,那么就可能导致内容产生混乱.(可以fork出多个子进程向同一个管道进行写操作给父进程数据).如果是一对一的关系就无所谓了,但是对于一对多就需要注意了.
 
管道缓冲区的大小由定义在头文件<limits.h>中的宏PIPE_BUF给出.在Linux系统中其值为4096.并且一旦写入PIPE_BUF个字节至管道后,进一步写管道的操作将阻塞直到有些字节已读出.

Linux内核态与用户态进程通信方法-用户上下文 http://www.linuxidc.com/Linux/2014-02/96883.htm

简单解析Linux下进程通信方法 http://www.linuxidc.com/Linux/2013-06/86341.htm

Linux的进程通信(IPC) http://www.linuxidc.com/Linux/2012-10/71887.htm

Linux 进程通信(System V) http://www.linuxidc.com/Linux/2012-03/57248.htm
 
 
二.FIFO特别文件
 
由于管道只能用于存在父子关系的进程之间的通信,为了满足非父子进程关系下的通信.可以用FIFO特别文件.
 
FIFO特别文件类似于管道,也是半双工方式,并且数据也是按先进先出顺序传送,因此的名FIFO.但是创建的方法与管道不同,管道式匿名通信通道,而FIFO特别文件通过调用mknod()被等级到文件系统,因此FIFO有时也成为有名管道.
 
与管道的主要不同有:
 
--FIFO作为特别文件存在于文件系统中
 
--不同祖先的进程可以通过FIFO特别文件共享数据
 
--当共享进程完成了所有IO操作后,除非unlink删除它,否则FIFO特别文件将存在文件系统中,并且可以留待下一次使用.
 
创建了FIFO文件之后,对于任何进程,只要知道了其名字并且有适当的访问权限,就能按照正常文件相同的方法打开它读或者写.
 
在某个进程读之前,必须有进程表示以写的方式打开这个文件,否则读进程则会一直阻塞.
 
同理,在写之前也一定要有进程打开了读,否则一样阻塞.
 
1.创建FIFO文件
 
int mkfifo(const char *path,mode_t mode);
 
int mknod(const char *path,mode_t mode,dev_t dev);
 
mkfifo创建一个FIFO特别文件,用参数path来指定其路径和文件名.mode参数则用来设置文件的权限.取值和open函数一样.
 
mknod创建一个给定文件类型的新文件,path同mkfifo.文件类型由mode参数给出,可选的值如下:
 S_IFIFO  这个就是特别文件
 
S_IFCHR  字符特别文件(不可移植)
 
S_IFDIR  目录文件(不可移植)
 
S_IFBLK  块特别文件(不可移植)
 
S_IFREG  普通文件(不可移植)
 
除开这些个参数,mode还需要另外附加上文件的访问方式,用获得方式组合宏定义.mknod似乎是比mkdir之类函数更底层的函数.
 
并且这个mode还受umask的修正,对于mkfifo则不受其影响.
 
由于刚打开时可能造成阻塞(读方式打开没有写进程,写操作打开没有读进程),并且打开文件的时候可以用O_NONBLOCK标志.第一次操作这个文件,并且打开方式使用了O_NONBLOCK的时候,open函数会返回-1,并且设置errno为错误值.
 
2.读写FIFO文件
 
和管道不同,由于打开FIFO文件可以使用O_NONBLOCK标志.所以要复杂一些.
 
没有O_NONBLOCK的时候读,如果没有可以读的,那么就会阻塞.有O_NONBLOCK的话,那么就直接返回-1,并且设置errno为EAGAIN了.
 
正常情况下如果文件写满了再调用write,那么会一直阻塞,知道信息被读走.完成操作时,返回写入的字节数.当用了O_NONBLOCK打开的时候,那么不能写则会返回-1,表示没有写进任何数据.errno也设置为EAGAIN.
 
 
原子性和管道一致.对于多个写一个读的时候,最好保证write的进程是不没有使用O_NONBLOCK的.并且每次写的时候,写入的数据小于PIPE_BUF的大小.保证写入数据的完整性.

更多详情见请继续阅读下一页的精彩内容http://www.linuxidc.com/Linux/2014-06/103322p2.htm

linux
相关资讯       Linux进程通信 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

��      

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款