加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux 管道--转

发布时间:2020-12-13 14:05:58 所属栏目:Linux 来源:网络整理
导读:h1 class="title_txt"linux 管道? div class="blogstory" 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。 有名管道叫na

<h1 class="title_txt">linux 管道?
<div class="blogstory">

管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。

有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建。

Linux管道的实现机制

在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:

·??????限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不象文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。

·??????读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。

注意:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。

1. 管道的结构

?????在?Linux?中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个?file?结构指向同一个临时的?VFS?索引节点,而这个?VFS?索引节点又指向一个物理页面而实现的。

2.管道的读写

??????管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数pipe_wrtie()。管道写函数通过将字节复制到?VFS?索引节点指向的物理内存而写入数据,而管道读函数则通过复制物理内存中的字节而读出数据。当然,内核必须利用一定的机制同步对管道的访问,为此,内核使用了锁、等待队列和信号。

?????当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的?file?结构。file?结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。写入函数在向内存中写入数据之前,必须首先检查?VFS?索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:

???????·内存中有足够的空间可容纳所有要写入的数据;

???????·内存没有被读程序锁定。

如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。否则,写入进程就休眠在?VFS?索 引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入 数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤 醒。

?????管 道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可 以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

???因为管道的实现涉及很多文件的操作,因此,当读者学完有关文件系统的内容后来读pipe.c中的代码,你会觉得并不难理解。

Linux 管道的创建和使用都要简单一些,唯一的原因是它需要更少的参数。实现与 Windows 相同的管道创建目标,Linux 和 UNIX 使用下面的代码片段:创建 Linux 命名管道int fd1[2];

???????? if(pipe(fd1))

??????? {?printf("pipe() FAILED: errno=%d",errno);

????????????? return 1;

???????? }Linux 管道对阻塞之前一次写操作的大小有限制。 专门为每个管道所使用的内核级缓冲区确切为 4096 字节。 除非阅读器清空管道,否则一次超过 4K 的写操作将被阻塞。 实际上这算不上什么限制,因为读和写操作是在不同的线程中实现的。Linux 还支持命名管道。对这些数字的早期评论员建议我,为公平起见,应该比较 Linux 的命名管道和 Windows 的命名管道。我写了另一个在 Linux 上使用命名管道的程序。我发现对于 Linux 上命名的和未命名的管道,结果是没有区别。Linux 管道比 Windows 2000 命名管道快很多,而 Windows 2000 命名管道比 Windows XP 命名管道快得多。

例子:

#include

<span style="color: #0000ff;">int<span style="color: #000000;"> main()
{
<span style="color: #0000ff;">int n,fd[<span style="color: #800080;">2]; <span style="color: #008000;">//<span style="color: #008000;"> 这里的fd是文件描述符的数组,用于创建管道做准备的
<span style="color: #000000;">pid_t pid;
<span style="color: #0000ff;">char line[<span style="color: #800080;">100<span style="color: #000000;">];
<span style="color: #0000ff;">if(pipe(fd)<<span style="color: #800080;">0) <span style="color: #008000;">//<span style="color: #008000;"> 创建管道
printf(<span style="color: #800000;">"<span style="color: #800000;">pipe create error/n<span style="color: #800000;">"<span style="color: #000000;">);

<span style="color: #0000ff;">if((pid=fork())<<span style="color: #800080;">0) <span style="color: #008000;">//<span style="color: #008000;">利用fork()创建新进程
printf(<span style="color: #800000;">"<span style="color: #800000;">fork error/n<span style="color: #800000;">"<span style="color: #000000;">);

<span style="color: #0000ff;">else <span style="color: #0000ff;">if(pid><span style="color: #800080;">0){ <span style="color: #008000;">//<span style="color: #008000;">这里是父进程,先关闭管道的读出端,然后在管道的写端写入“hello world"
close(fd[<span style="color: #800080;">0<span style="color: #000000;">]);
write(fd[<span style="color: #800080;">1],<span style="color: #800000;">"<span style="color: #800000;">hello word/n<span style="color: #800000;">",<span style="color: #800080;">11<span style="color: #000000;">);
}
<span style="color: #0000ff;">else<span style="color: #000000;">{
close(fd[<span style="color: #800080;">1]); <span style="color: #008000;">//<span style="color: #008000;">这里是子进程,先关闭管道的写入端,然后在管道的读出端读出数据
n= read(fd[<span style="color: #800080;">0],line,<span style="color: #800080;">100<span style="color: #000000;">);
write(STDOUT_FILENO,n);
}
exit(<span style="color: #800080;">0<span style="color: #000000;">);
}

来源不可知,转载地址:http://blog.csdn.net/mtv0312/article/details/6183583

管道通信,就是在2个进程间建立一个管道

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读