• Linux——进程间通信——管道(文件)通信


    目录

    前言

    一、有名管道

    1、用法

    2、管道分类

    3、有名管道的创建

    4、思考:如何进程a要将键盘获取的数据传递给另一个进程b?

     5、有名管道实现进程间通信

    二、无名管道

    1、无名管道的创建

    2、管道操作分为以下步骤

    3、无名管道实现进程间通信

    前言

    进程间通信方法:

    (1)管道

    (2)信号量

    (3)共享内存

    (4)消息队列

    (5)套接字

    一、有名管道

    1、用法

    • | 命令
    • 举例:ps -ef|grep "sleep"

    两个进程通信:比如a,b进程,a想管道中写入数据,b读取数据;

    2、管道分类

    (1)有名管道

    (2)无名管道

    区别:有名管道可以在任意进程间通信;无名管道主要在父子进程间通信(重点)

    3、有名管道的创建

    ①命令:mkfifo  (属于系统调用)

    ②打开管道:open()

    ③读数据:read()

    ④写数据:write()

    ⑤关闭管道:close()

    4、思考:如何进程a要将键盘获取的数据传递给另一个进程b?

    (不能用文件传递),效率太慢。

    创建管道之后,它会在内存上分配一块空间,表面上卡把数据写入管道中了,实际上是吧数据写入内存中了。另外一个程序是从内存中读取数据的,所以效率是比较高的。

    管道文件的大小永远为0。如下图所示:

     5、有名管道实现进程间通信

    (1)参考代码:

    1. //a.c
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main()
    9. {
    10. int fd=open("fifi",O_WRONLY);
    11. assert(fd!=-1);
    12. printf("fd=%d\n",fd);
    13. write(fd,"hello",5);
    14. close(fd);
    15. }
    16. //加入循环后:
    17. //c.c
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. int main()
    25. {
    26. int fd=open("fifi",O_WRONLY);
    27. assert(fd!=-1);
    28. // printf("fd=%d\n",fd);
    29. while(1)
    30. {
    31. printf("input:\n");
    32. char buff[128]={0};
    33. fgets(buff,128,stdin);
    34. if(strncmp(buff,"end",3)==0)
    35. {
    36. break;
    37. }
    38. write(fd,buff,strlen(buff));
    39. }
    40. close(fd);
    41. }
    1. //b.c
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main()
    9. {
    10. int fd=open("./fifi",O_RDONLY);
    11. assert(fd!=-1);
    12. printf("fd=%d\n",fd);
    13. char buff[128]={0};
    14. read(fd,buff,127);
    15. printf("read:%s\n",buff);
    16. close(fd);
    17. }
    18. //加入循环后:
    19. //d.c
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. int main()
    27. {
    28. int fd=open("./fifi",O_RDONLY);
    29. assert(fd!=-1);
    30. printf("fd=%d\n",fd);
    31. while(1)
    32. {
    33. char buff[128]={0};
    34. if(read(fd,buff,127)==0)
    35. {
    36. break;
    37. }
    38. printf("read:%s\n",buff);
    39. }
    40. close(fd);
    41. }

     (2)管道的特点

    ①管道必须读、写进程同时open,否则会阻塞;

    • 阻塞的情况:(只有写进程open或只有读进程open)

     

     正确的通信:读写进程同时open(打开两个窗口)

    ②如果管道中没有数据,那么read就会阻塞。

    ③管道的写端关闭,读read返回值为0;

    ④管道打开的时候只读和只写方式,读写方式是未定义的。

    ⑤管道是半双工的(某一时刻只能选择一个方向)(重点)

        通信方式:单工、半双工、全双工。

    ⑥无论有名还是无名, 写入管道的数据都在内存中。(重点)

     ⑧管道的读端关闭,写会产生异常(发送信号SIGPIPE)(可以改变信号的响应方式验证一下)。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. //发送信号
    9. void fun(int sig)
    10. {
    11. printf("sig=%d\n",sig);
    12. }
    13. int main()
    14. {
    15. signal(SIGPIPE,fun);
    16. int fd=open("fifi",O_WRONLY);
    17. assert(fd!=-1);
    18. // printf("fd=%d\n",fd);
    19. while(1)
    20. {
    21. printf("input:\n");
    22. char buff[128]={0};
    23. fgets(buff,128,stdin);
    24. if(strncmp(buff,"end",3)==0)
    25. {
    26. break;
    27. }
    28. write(fd,buff,strlen(buff));
    29. }
    30. close(fd);
    31. }

    二、无名管道

    使用pipe创建无名管道,**只能进行父子间的通信;

    pipe是一个系统调用

    1、无名管道的创建

    int pipe(int fds[2]);
    //pipe()成功返回0,失败返回-1;
    //fds[0]是管道读端的描述符
    //fds[1]是管道写端的描述符

    2、管道操作分为以下步骤

    (1)父进程调用pipe函数开辟管道,得到两个文件描述符指向管道的两端;

    (2)父进程用fork创建子进程,那么子进程也有两个文件描述符指向同一管道;

    (3)父进程关闭管道文件读端,子进程关闭写端。父进程可以往管道里写数据,子进程可以从管道中读数据,这样就在父子进程之间建立管道,实现进程间通信。

    3、无名管道实现进程间通信

    参考代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main()
    7. {
    8. int fd[2];
    9. assert(pipe(fd)!=-1);
    10. pid_t pid=fork();//先open,再fork,父子进程共享打开的文件描述符
    11. assert(pid!=-1);
    12. if(pid==0)
    13. {
    14. close(fd[1]);
    15. char buff[128]={0};
    16. read(fd[0],buff,127);
    17. printf("child read:%s\n",buff);
    18. close(fd[0]);
    19. }
    20. else
    21. {
    22. close(fd[0]);
    23. write(fd[1],"hello",5);
    24. close(fd[1]);
    25. }
    26. exit(0);
    27. }

    如有错误,敬请指正。

    您的收藏与点赞都是对我最大的鼓励和支持!

  • 相关阅读:
    猿创征文 第二季| #「笔耕不辍」--生命不息,写作不止#
    MMU的28问,你能回答几个
    点云从入门到精通技术详解100篇-基于几何特征的三维点云配准(续)
    云服务器ubuntu18.04挂载数据盘
    中国金刚石工具市场发展现状及供需格局分析预测报告
    XML 测试用例分类Variants参数
    Unity - BRP管线关闭 - UpdateDepthTexture的绘制
    PowerBI商学院佐罗BI真经连续剧
    从零搭建开发脚手架 顺应潮流开启升级 - SpringBoot 从2.x 升级到3.x
    使用 hint 进行数据库内排序
  • 原文地址:https://blog.csdn.net/x20020402/article/details/127623314