• 系统编程 day10 管道的知识 (无名管道 ,有名管道 ,管道通信,管道的函数,管道的知识(什么是管道 ,,,) )


    1.管道基本概念

    管道是针对于本地计算机的两个进程之间的通信而设计的通信方法,管道建立后,实际获得两个文件描述符:一个用于读取而另外一个用于写入。

     管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管道。

    无名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。 命名管道单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是单独构成一种文件系统。

    数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。


    2.管道基本概念二

    管道通信:是利用FIFO排队模型来指挥进程间的通信。把它当作是连接两个实体的一个单向连接器

    使用管道的命令实例: ls -1 | wc -l 该命令首先创建两个进程,

    一个对应于ls –1,另一个对应于wc –l。

    然后,把第一个进程的标准输出设为第二个进程的标准输入。它的作用是计算当前目录下的文件数量。


    3.无名管道


    4.无名管道的特点:

    1.只能用于具有亲缘关系的进程之间的通信

    2.半双工的通信模式

    3.具有固定的读端和写端 管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数。


    5.管道创建与关闭

    管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。

    其中fd[0]固定用于读管道,而fd[1]固定用于写管道。 构成了一个半双工的通道。

     


    6.无名管道的创建 函数

    pipe(建立管道)

    头文件 #include

    定义函数 int pipe(int filedes[2]);

    函数说明 pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。

    返回值 若成功则返回0,否则返回-1,错误原因存于errno中。

    错误代码 EMFILE 进程已用完文件描述词最大量。

                    ENFILE 系统已无文件描述词可用。

                    EFAULT 参数filedes数组地址不合法。


    7.代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:管道的功能
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. //1.pipe 管道功能的使用
    37. //功能:创建一个管道
    38. //参数: int fds[[2]
    39. //返回值 : 0成功 -1失败
    40. //
    41. //2.创建一个管道 ,并且在尾部写入,头部读取
    42. //
    43. int main(int argc,char *argv[])
    44. {
    45. int fds[2]={0};
    46. //创建一个管道
    47. if(pipe(fds)<0)
    48. {
    49. printf("%d %s\n",errno,strerror(errno));//strerror函数的作用就是将错误码给转化成错误信息。
    50. }
    51. printf("read fds[0] =%d\t write fds[1]=%d\n ",fds[0],fds[1]);
    52. char buff[100]={"你abc"};
    53. int a =strlen(buff);
    54. printf("字符串的长度: %d\n",a);
    55. int len =write(fds[1],buff,strlen(buff)); //写入数据到 写端
    56. printf("len =%d\n",len);
    57. bzero(buff,sizeof(buff));//清空字符数组
    58. len =read(fds[0],buff,sizeof(buff));//读一下
    59. printf("buff is %s len= %d\n",buff,len);
    60. close(fds[0]);
    61. close(fds[1]);
    62. return 0;
    63. }


    8.程序功能:父子进程之间的管道操作 

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:父子进程之间的管道操作 多次
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. //多次读写
    37. //
    38. int main(int argc,char *argv[])
    39. {
    40. int fds[2]={0};
    41. if(pipe(fds)<0)//创建管道
    42. {
    43. printf("%d %s \n",errno,strerror(errno));
    44. return -2;
    45. }
    46. char buff1[100]={"abcdefg"};
    47. pid_t pid =fork();
    48. if(pid <0)
    49. {
    50. perror("fork error\n");
    51. return -1;
    52. }
    53. else if(pid ==0)//子进程
    54. {
    55. //char buff1[100]={"abcdefg"};
    56. int len =write(fds[1],buff1,strlen(buff1)); //写入数据 第一次
    57. if(len<0)
    58. {
    59. printf("write error\n");
    60. }
    61. else
    62. {
    63. printf("write :len :%d\n",len);
    64. }
    65. len =write(fds[1],buff1,strlen(buff1)); //写入数据 第二次
    66. if(len<0)
    67. {
    68. printf("write error\n");
    69. }
    70. else
    71. {
    72. printf("write :len :%d\n",len);
    73. }
    74. }
    75. else if(pid >0) //父进程
    76. {
    77. wait(NULL);
    78. char buff[100];
    79. bzero(buff,sizeof(buff));
    80. int len1 = read(fds[0],buff,sizeof(buff));
    81. if(len1<0)
    82. {
    83. perror("read error\n");
    84. }
    85. else
    86. {
    87. printf("read : %s\n",buff);
    88. }
    89. }
    90. return 0;
    91. }


    9.程序功能:父子进程 无名管道 多次写 一次读

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. //1.popen pclose
    37. //2.popen 高级管道 标准管道
    38. //3.
    39. int main(int argc,char *argv[])
    40. {
    41. //fp 是标准管道流指针
    42. FILE * fp =popen("ls -l","r");//r 可读的方式
    43. if(fp==NULL)
    44. {
    45. printf("%d %s\n",errno ,strerror(errno));
    46. return -2;
    47. }
    48. char buff[1024]="";
    49. fread(buff,1024,1,fp);
    50. fwrite(buff,strlen(buff),1,stdout);
    51. pclose(fp);
    52. return 0;
    53. }

    10.//1.popen  pclose   函数

    popen(建立管道I/O)

    头文件 #include

    定义函数 FILE * popen( const char * command,const char * type);

    函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。

    返回值 若成功则返回文件指针,否则返回NULL,错误原因存于errno中。

    错误代码 EINVAL参数type不合法。 注意事项 在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。

    pclose(关闭管道I/O)

    头文件 #include

    定义函数 int pclose(FILE * stream);

    函数说明 pclose()用来关闭由popen所建立的管道及文件指针。

    参数stream为先前由popen()所返回的文件指针。

    返回值 返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。

    错误代码 ECHILD pclose()无法取得子进程的结束状态。

     

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. //1.popen pclose
    37. //2.popen 高级管道 标准管道
    38. //3.
    39. int main(int argc,char *argv[])
    40. {
    41. //fp 是标准管道流指针
    42. FILE * fp =popen("ls -l","r"); //r 可读的方式
    43. if(fp==NULL)
    44. {
    45. printf("%d %s\n",errno ,strerror(errno));
    46. return -2;
    47. }
    48. char buff[1024]="";
    49. fread(buff,1024,1,fp);
    50. fwrite(buff,strlen(buff),1,stdout); //写到屏幕上
    51. pclose(fp);//关闭管道
    52. return 0;
    53. }

    11.mkfifo  创建有名管道 

    头文件 #include #include

    定义函数 int mkfifo(const char * pathname,mode_t mode);

    函数说明 mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限,因此mode值也会影响到FIFO文件的权限。当使用open()来打开FIFO文件时O_NONBLOCK旗标会有影响

    1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。

    2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。反之亦是如此

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:mkfifo 创建有名管道
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. //有名管道
    37. //1.程序运行结束之后 有具体的文件存在 
    38. //2.非亲缘之间也可以进行通信
    39. //3.没有固定的读写端
    40. //4.无名有名管道 都不可以用lseek 来定位
    41. //文件必须不存在
    42. //读写必须同步,写完就读 ,否则在短时间(进程结束以后)内会消失  
    43. // 
    44. int main(int argc,char *argv[])
    45. {
    46. char str[100]={"pipe"};
    47. if(mkfifo(str,0666)<0)
    48. {
    49. perror("mkfifo error\n");
    50. return -1;
    51. }
    52. else
    53. {
    54. printf("mkfifo ok\n");
    55. }
    56. int fd=open(str,O_RDWR);
    57. char buff[2000]={"-----------------------\n"};
    58. write(fd,buff,strlen(buff));
    59. char buff1[200]="";
    60. read(fd,buff1,sizeof(buff));
    61. fputs(buff1,stdout);
    62. unlink(str); //删除文件 pipe
    63. return 0;
    64. }


    12.程序 :测试系统  有多少个文件描述符号

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:有多少个文件描述符号
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. int main(int argc,char *argv[])
    37. {
    38. int fd=0;
    39. while((fd=open("a.txt",O_CREAT|O_RDWR,0666))!=-1)
    40. {
    41. printf("fd =%d\n",fd);
    42. }
    43. return 0;
    44. }


     

     

  • 相关阅读:
    RNA 24. SCI文章中基于TCGA的免疫浸润细胞分析的在线小工具——TIMER
    Go语言入门心法(十五):Go微服务实战
    Matter理论教程-通用-1-01:理论详解
    【数字电路与逻辑设计实验】——Multisim仿真实验-xx进制的计数器
    Kubernetes(K8s)上使用分布式存储(Distributed Storage)
    【ACWing 算法基础】栈和队列(用数组构造栈和队列)
    HTML_案例1_注册页面
    R语言glm函数构建二分类logistic回归模型(family参数为binomial)、使用AIC函数比较两个模型的AIC值的差异(简单模型和复杂模型)
    12:面试题:react,vue中的key有什么作用?(key的内部原理)
    GBASE 8s 如何通过脚本获取bufwait等统计信息
  • 原文地址:https://blog.csdn.net/she666666/article/details/126273088