实例2:尝试使用管道读写数据
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>int main(){int pipefd[2];int ret = pipe(pipefd);if (ret == -1){// 管道创建失败perror("make piep");exit(-1);}char buf[64] = "hello world";// 写数据write(pipefd[1], buf, sizeof(buf)/sizeof(buf[0]));// 读数据memset(buf,0,sizeof(buf));// 清空bufssize_t s = read(pipefd[0], buf, 11);buf[s] = '\0';printf("%s\n", buf);return 0;}//成功输出hello world
可以看见对管道的操作,实际上就是对两个读写文件的操作,本质就是对文件的操作和使用 。
管道的本质Linux下一切皆文件,看待管道,其实时可以像看待文件一样 。且管道和文件使用方法是一致的 。管道的生命周期随进程 。
父子进程通过匿名管道通信原理:匿名管道是提供给有亲缘关系两个进程进行通信的 。所以我们可以在创建管道之后通过fork函数创建子进程,这样父子进程就看到同一份资源,且父子进程都有这个管道的读写文件描述符 。我们可以关闭父进程的读端,关闭子进程的写端,这样子进程往管道里面写数据,父进程往管道里面读数据,这样两个进程就可以实现通信了 。原理解读:
fork函数调用成功后,将为子进程申请PCB和用户内存空间,子进程是父进程的副本,在用户空间将复制父进程用户空间所有的数据(代码段、数据段、BBS、栈、堆,实际上是复制的父进程的虚拟空间的地址),子进程从父进程继承下列属性:有效用户、组号、进程组号、环境变量、信号处理方式设置、信号屏蔽集合、当前工作目录、根目录、文件模式掩码、文件大小限制和打开的文件描述符(特别注意:共享同一文件表项) 。
共享同一文件表项就造成了一种现象,父子进程无论谁对文件进行操作,那么另外一个进程的文件表也会受到相同的影响 。
文章插图
从图中可以看出,虽然在子进程的表项中式复制了关于打开文件的信息,但是他们是共享文件表的,所以如果一个进程对文件指针进行移动,那么肯定会影响到另外的进程 。
思考:这是不是和写时拷贝相违背了,为什么文件表就能共享了呢?
要知道在linux源码中,每个进程都存在一个PCB结构体,每个PCB中,存放了一个结构体指针指向一个我们理解为文件描述符的结构体struct file,而这个结构体里,才存了文件的id,值得注意的是,这个结构体里有一个指针才是指向真正文件的 。文件系统存在于磁盘当中,对磁盘的操作操作系统不会拷贝一份文件给子进程,相反,像那些临时创建存放于堆区和栈区的数据,操作系统会采用写时拷贝,进行复制 。
文章插图
总结:父子进程共享文件表,对文件表进行的任何操作都会对父子进程造成相同的影响,与写时拷贝进行区分 。
父子进程通过创建匿名管道通信具体过程如下:
1.父进程创建管道(管道创建要在进程创建之前)
文章插图
2.fork创建子进程(子进程继承父进程的管道文件描述符)
文章插图
3.关闭父进程的写段,子进程的读端
文章插图
实例演示: 子进程每隔1秒往管道里面写数据,父进程每隔1秒往管道里读数据
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>int main(){int pipefd[2];int ret = pipe(pipefd);if (ret == -1){// 管道创建失败perror("make piep");exit(-1);}pid_t id = fork();if (id < 0){perror("fork failed");exit(-1);}else if (id == 0){// child// 关闭读端close(pipefd[0]);const char* msg = "I am child...!\n";//int count = 0;// 写数据while (1){ssize_t s = write(pipefd[1], msg, strlen(msg));printf("child is sending message...\n");sleep(1);}}else{// parentclose(pipefd[1]);char buf[64];while (1){ssize_t s = read(pipefd[0], buf, sizeof(buf)/sizeof(buf[0])-1);if (s > 0){buf[s] = '\0';// 字符串后放一个'\0'printf("father get message:%s", buf);}else if (s == 0){// 读到文件结尾写端关闭文件描述符 读端会读到文件结尾printf("father read end of file...\n ");}sleep(1);}}return 0;}
经验总结扩展阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一篇了解全MVCC
- 2022感恩节是在什么时候 2022年感恩节日期是哪一天几月几日
- 治疗二型糖尿病偏方
- 鬼针草治疗高血压偏方
- 2022美国感恩节是哪一天 2022美国感恩节有几天假期
- 2023年感恩节是几月几号 2023年感恩节是哪一天
- 酒后反胃恶心吐怎么办
- 最经典早安祝福语
- 哺乳期吃了一个脏脏包对孩子有什么影响
- 早安问候文案唯美