管道代码及分析.txt
来源:互联网 发布:中国传媒大学网络 编辑:程序博客网 时间:2024/05/16 11:52
管道
管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,前者可用于具有亲缘关系进程间的通信,即可用于父进程和子进程间的通信,后者克服了管道没有名字的限制,因此,除具有前者所具有的功能外,它还允许无亲缘关系进程间的通信,即可用于运行于同一台机器上的任意两个进程间的通信。
无名管道由pipe()函数创建:
#include <unistd.h>
int pipe(int filedis[2]);
参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。 无名管道占用两个文件描述符, 不能被非血缘关系的进程所共享, 一般应用在父子进程中.
在父进程中关闭 fildes[0], 向 fildes[1]写入数据; 在子进程中关闭 filedes[1], 从
fildes[0]中读取数据可实现从父进程流向子进程的管道.
在进程的通信中, 我们无法判断每次通信中报文的字节数, 即无法对数据流进行自行拆分, 侧耳发生了上例中子进程一次性读取父进程两次通信的报文情况.
管道是进程之间的一种单向交流方法, 要实现进程间的双向交流, 就必须通过两个管道来完成. 双向管道流的创立过程如下:
(1) 创建管道, 返回两个无名管道文件描述符 fildes1 和 fildes2:
(2) 创建子进程, 子进程中继承管道 fildes1 和 fildes2.
(3) 父进程关闭只读文件描述符 fildes1[0], 只写描述符 fildes2[1]
(4) 子进程关闭只写文件描述符 fildes1[1], 只读描述符 fildes2[0]
创建的结果如下:
父进程 --写--> fildes1[1] --管道--> fildes1[0] --读--> 子进程
父进程 <--读-- fildes2[0] <--管道-- fildes2[1] <--写-- 子进程
这里实现一个父子进程间双向通信的实例: 父进程先向子进程发送两次数据, 再接收子进程传送刚来
的两次数据.
为了正确拆分时间留从父进程流向子进程的管道采用'固定长度'方法传送数据; 从子进程流向
父进程的管道采用'显式长度'方法传回数据.
(1) 固定长度方式
char bufG[255];
void WriteG(int fd, char *str, int len){
memset(bufG, 0, sizeof(bufG));
sprintf(bufG, "%s", str);
write(fd, bufG, len);
}
char *ReadG(int fd, int len){
memset(bufG, 0, sizeof(bufG));
read(fd, bufG, len);
return(bufG);
}
在此设计中, 父子程序需要约定好每次发送数据的长度; 且长度不能超过 255 个字符.
(2) 显式长度方式
char bufC[255];
void WriteC(int fd, char str[]){
sprintf(bufC, "%04d%s", strlen(str), str);
write(fd, bufC, strlen(bufC));
}
char *ReadC(int fd){
int i, j;
memset(bufC, 0, sizeof(bufC));
j = read(fd, bufC, 4);
i = atoi(bufC);
j = read(fd, bufC, i);
return(bufC);
}
父子进程约定在发送消息前先指明消息的长度.
(3) 主程序
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
int main()
{
int fildes1[2], fildes2[2];
pid_t pid;
char buf[255];
assert(pipe(fildes1) == 0);
assert(pipe(fildes2) == 0);
assert((pid = fork()) >= 0);
if(pid == 0){
close(fildes1[1]);
close(fildes2[0]);
strcpy(buf, ReadG(fildes1[0], 10));
fprintf(stderr, "[child] buf = [%s]\n", buf);
WriteC(fildes2[1], buf);
strcpy(buf, ReadG(fildes1[0], 10));
fprintf(stderr, "[child] buf = [%s]\n", buf);
WriteC(fildes2[1], buf);
return(0);
}
close(fildes1[0]);
close(fildes2[1]);
WriteG(fildes1[1], "hello!", 10);
WriteG(fildes1[1], "world!", 10);
fprintf(stderr, "[father] buf = [%s] \n", ReadC(fildes2[0]));
fprintf(stderr, "[father] buf = [%s] \n", ReadC(fildes2[0]));
return 0;
}
在Linux系统下,有名管道可由两种方式创建:命令行方式mknod系统调用和函数mkfifo。
下面的两种途径都在当前目录下生成了一个名为myfifo的有名管道:
方式一:mkfifo("myfifo","rw");
方式二:mknod myfifo p
生成了有名管道后,就可以使用一般的文件I/O函数如open、close、read、write等来对它进行操作。
管道是 UNIX 中最古老的进程间通信工具, 它提供了进程之间的一种单向通信的方法.
popen 模型
从前面的程序可以看出, 创建连接标准 I/O 的管道需要多个步骤, 这需要使用大量的代码, UNIX 为了
简化这个操作, 它提供了一组函数实现之. 原型如下:
#include <stdio.h>
FILE *popen(const char *command, char *type);
int pclose(FILE *stream);
函数 popen 调用成功时返回一个标准的 I/O 的 FILE 文件流, 其读写属性由参数 type 决定.
这里看一个模拟 shell 命令'ps -ef | grep init'的实例.
[bill@billstone Unix_study]$ cat pipe3.c
#include <stdio.h>
#include <assert.h>
int main()
{
FILE *out, *in;
char buf[255];
assert((out = popen("grep init", "w")) != NULL); // 创建写管道流
assert((in = popen("ps -ef", "r")) != NULL); // 创建读管道流
while(fgets(buf, sizeof(buf), in)) // 读取 ps -ef 的结果
fputs(buf, out); // 转发到 grep init
pclose(out);
pclose(in);
return 0;
}
有名管道 FIFO
FIFO 可以在整个系统中使用.
在 Shell 中可以使用 mknod 或者 mkfifo 命令创建管道; 而在 C 程序中, 可以使用 mkfifo 函数创建有名管道.
要使用有名管道, 需要下面几个步骤:
(1) 创建管道文件
(2) 在某个进程中以只写方式打开管道文件, 并写管道
(3) 在某个进程中以只读方式打开管道文件, 并读管道
(4) 关闭管道文件.
低级文件编程库和标准文件编程库都可以操作管道. 管道在执行读写操作之前, 两端必须同时打开, 否
则执行打开管道某端操作的进程将一直阻塞到某个进程以相反方向打开管道为止.
- 管道代码及分析.txt
- 进程间通信:管道及命名管道(代码实现)
- 管道及有名管道
- 管道及有名管道
- 管道及有名管道
- 基于管道的进程间通信代码分析
- 命名管道客户端及服务器端简单代码示例
- 过滤器:管道过滤器技术特点及性能分析
- c#读mif文件及txt文件代码
- linux2.6 makefiles.txt学习及实例分析
- linux2.6 makefiles.txt学习及实例分析
- linux2.6 makefiles.txt学习及实例分析
- linux--管道及管道容量
- ms05016分析及测试代码
- 红色代码分析及清除
- ADB结构及代码分析
- bootchart 使用说明及代码分析
- AbstractQueuedSynchronizer原理及代码分析
- 用SQL取差集--5月11日的一次任务
- html5 多颗子弹-1
- 05-web应用组织结构和web.xml文件的作用
- 天龙八部的BillingServer
- SystemProperties_SOP
- 管道代码及分析.txt
- Word2003中Visio2003图打印错误的解决方法
- poj1002 487-3279(STL map应用)
- AndroidNote013.在百度地图上画出轨迹
- 线索二叉树的基本操作
- 解决下载Android源码时遇到的问题
- Php学习笔记(一)
- STL容器数据结构
- Django常见问题