管道
管道这个方式个人感觉真的是非常简单的,先简述一下管道的概念:
管道的概念就是这些,需要注意一下的是什么是伪文件,还有就是半双工这两个概念。
伪文件:
这里管道的伪文件其实就是一块内核的缓冲区,把数据都放在这片缓冲区里面然后进行读写操作,伪文件系统是一个linux里面的一个概念,有兴趣的可以查阅一下相关的资料,有很多种伪文件,都代表不懂得意义。
半双工通信方式:
这个概念的话如果有一些嵌入式基础的会好理解的多,嵌入式里面有各种通信方式,单工,半双工,全双工这些。
半双工就是指数据可以在一个信号载体的两个方向上传输,但是不能同时传输,比如我这边可以读写你那边也能读写,但是我读的时候我不能写入,我写入的时候不能读取,在某一时刻数据只能在某一个方向流动,这就是半双工,单工就是完全单向的,全双工相应的就是读写可以同时进行的,在嵌入式里面的话有几个典型的半双工模式,例如I2C通信,RS-485等。
管道更加通俗易懂得来阐述它得概念的话就是字面意思了,就把它理解成一根水管,这根水管连接到了两个木桶里面或者两个池子里面,数据就是管道里面的水,如果我想从木桶A里面的水流到木桶B那么就需要把木桶A抬高,水流利用重力自然而然地从A到B,但是B不能到A,相反亦然。
概念理解了之后就只是如何使用的问题了,使用也十分简单,就仅仅一个pipe函数而已,pipe函数具体用法可以在linux得man page查看, man 2 pipe出现如下页面
int pipe(int pipefd[2]);
函数原型可以看出返回值是int型,默认的失败返回-1的然后参数里面的 int pipefd[2]这是一个传入参数,需要我们在外部定义一个包含两个文件描述符的数组,这个数组就是我们的管道,很简单,如果我们需要调用这个管道那么就只需要在创建出来的管道里面用wirte(fd[1],...,...), 这个value就是你需要传入的值,这里1定义为写入,0定义为读取,如果你需要读取数据就只需要read(fd[0],...,...),十分的简单。
下面的 int pipe2(int pipefd[2], int flags);
多了一个flags参数,这个参数在下面也有详细的说明,这里不细说了。
需要注意一下:
1.pipe只能在有血缘关系的进程里面进行使用,且pipe的调用必须要在fork之前。
这个应该很好理解,毕竟pipe管道应该是在父进程开辟,且子进程要继承它,如果在fork之后调用的话就是父子进程同时创建管道就会有两个管道了
2.管道使用完毕后应该及时的关闭掉。
关闭的方式就是调用一次close(pipefd[x]);
3.pipe开辟的管道成为匿名管道,如果需要在非血缘关系间进行使用的话,需要使用有名管道。
贴一个pipe的示例程序代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int fd[2];// fd[0] read fd[1] write
pid_t pid;
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe error");
return 0;
}
pid = fork();
if(pid == -1)
{
perror("fork error");
return 0;
}
if(pid == 0)
{
close(fd[1]);
char buf[1024];
ret = read(fd[0],buf,sizeof(buf));
if(ret == 0)
{
printf("----------\n\n");
}
write(STDOUT_FILENO,buf,ret);
}
else{
close(fd[0]);
write(fd[1],"这个很牛逼的数据\n",strlen("这个很牛逼的数据\n"));
}
return 0;
}