匿名沟通渠道

管道Linux最初支持Unix IPC其中的一种形式。具有下列特征:

1.管道是半双工。数据可以仅在一个方向流动;当双方需要沟通。建设两条管线需要。

2.仅仅能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

什么是管道

管道对于管道两端的进程而言,就是一个文件。但它不是普通的文件,它不属于某种文件系统。而是自立门户,单独构成一种文件系统,而且仅仅存在与内存中。

数据的读出和写入

一个进程向管道中写的内容被管道还有一端的进程读出。写入的内容每次都加入在管道缓冲区的末尾。而且每次都是从缓冲区的头部读出数据。

管道的创建

#include int pipe(int fd[2])

管道两端可分别用描写叙述字fd[0]以及fd[1]来描写叙述,须要注意的是,管道的两端是固定了任务的。即一端仅仅能用于读,由描写叙述字fd[0]表示,称其为管道读端;还有一端则仅仅能用于写,由描写叙述字fd[1]来表示,

管道的规则

1.      当管道内容长度为0时,读端将处于堵塞状态,等待写端向管道写入内容

2.      当写端数据长度小于缓冲区长度时。数据将以原子性写入缓冲区。

对读进程来说:

3.      当写端被关闭时。全部数据被读出后,read返回0。

4.      当写端未被关闭时。全部数据被读出后。读端堵塞。

对写进程来说:

5.      当读端关闭时,如写端数据长度大于管道最大长度时,写完管道长度时。产生信号SIGPIPE后退出程序。

(以存入管道的数据读进程能够读取到)

6.      当读端未被关闭时。如写端数据长度大于管道最大长度时,写完管道长度时,写端将处于堵塞状态

规则分析1

  1. #include<unistd.h>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<sys/types.h>
  5. #include<stdlib.h>
  6. #include<sys/wait.h>
  7.  
  8. int main() {
  9. int fd[2];
  10. pid_t cid;
  11.  
  12. if (pipe(fd) == -1) {
  13. perror("管道创建失败!
  14.  
  15. ");
  16. exit(1);
  17. }
  18. cid = fork();
  19. switch (cid) {
  20. case -1:
  21. perror("子进程创建失败");
  22. exit(2);
  23. break;
  24. case 0:
  25. close(fd[1]);
  26. char message[1000];
  27. int num = read(fd[0], message, 1000);
  28. printf("子进程读入的数据是:%s,长度是=%d", message, num);
  29. close(fd[0]);
  30. break;
  31. default:
  32. close(fd[0]);
  33. char *writeMsg = "父进程写入的数据!
  34.  
  35. ";
  36. sleep(10);//1
  37. write(fd[1], writeMsg, strlen(writeMsg));
  38. close(fd[1]);
  39. break;
  40. }
  41. return 0;
  42. }

[root@ Release 18$] ps -C processcomm -opid,ppid,stat,cmd

PID  PPID STAT CMD

5973 2488 S   /root/workspace/processcomm/Release/processcomm

5976 5973 S   /root/workspace/processcomm/Release/processcomm

=>读端因为堵塞中。其所在进程(子进程)处于sleep状态

控制台输出

父进程工作PID=5973,PPID=2488

子进程工作PID=5976,PPID=5973

子进程读入的数据是:父进程写入的数据!

,长度是=27

规则分析2

  1. switch (cid) {
  2. case -1:
  3. perror("子进程创建失败");
  4. exit(2);
  5. break;
  6. case 0:
  7. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  8. break;
  9. default:
  10. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  11.  
  12. close(fd[0]);
  13. const long int writesize=4000;
  14. char writeMsg[writesize];
  15. int i;
  16. for(i=0;i<writesize;i++)
  17. {
  18. writeMsg[i]='a';
  19. }
  20. int writenum=write(fd[1], writeMsg, strlen(writeMsg));
  21. printf("父进程写入的数据长度是=%d\n", writenum);
  22. close(fd[1]);
  23. wait(NULL);
  24. break;
  25. }

控制台输出

父进程工作PID=7072,PPID=2488

父进程写入的数据长度是=4001

子进程工作PID=7077,PPID=7072

规则分析3

  1. switch (cid) {
  2. case -1:
  3. perror("子进程创建失败");
  4. exit(2);
  5. break;
  6. case 0:
  7. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  8. close(fd[1]);
  9. char message[40001];
  10. int num = read(fd[0], message, 4001);
  11. printf("子进程读入的数据长度是=%d\n", num);
  12. num = read(fd[0], message, 4000);
  13. printf("子进程再次读入的数据长度是=%d", num);
  14. close(fd[0]);
  15. break;
  16. default:
  17. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  18.  
  19. close(fd[0]);
  20. const long int writesize = 4000;
  21. char writeMsg[writesize];
  22. int i;
  23. for (i = 0; i < writesize; i++) {
  24. writeMsg[i] = 'a';
  25. }
  26. int writenum = write(fd[1], writeMsg, strlen(writeMsg));
  27. printf("父进程写入的数据长度是=%d\n", writenum);
  28. close(fd[1]);
  29. // wait(NULL);
  30. break;
  31. }

[root@ Release30$] ps -C processcomm -o pid,ppid,stat,cmd

PID PPID STAT CMD

=>读写进程都已退出

控制台输出

父进程工作PID=8004,PPID=2488

父进程写入的数据长度是=4001

子进程工作PID=8009,PPID=1

子进程读入的数据长度是=4001

子进程再次读入的数据长度是=0

规则分析4

  1. switch (cid) {
  2. case -1:
  3. perror("子进程创建失败");
  4. exit(2);
  5. break;
  6. case 0:
  7. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  8. char message[40001];
  9. int num = read(fd[0], message, 4001);
  10. printf("子进程读入的数据长度是=%d", num);
  11. num = read(fd[0], message, 4000);
  12. printf("子进程再次读入的数据长度是=%d", num);
  13. break;
  14. default:
  15. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  16. close(fd[0]);
  17. const long int writesize = 4000;
  18. char writeMsg[writesize];
  19. int i;
  20. for (i = 0; i < writesize; i++) {
  21. writeMsg[i] = 'a';
  22. }
  23. int writenum = write(fd[1], writeMsg, strlen(writeMsg));
  24. printf("父进程写入的数据长度是=%d\n", writenum);
  25. close(fd[1]);
  26. break;
  27. }

[root@ Release29$] ps -C processcomm -o pid,ppid,stat,cmd

PID PPID STAT CMD

7916    1 S   /root/workspace/processcomm/Release/processcomm

=>读进程堵塞

控制台输出:

父进程工作PID=7914,PPID=2488

父进程写入的数据长度是=4001

子进程工作PID=7916,PPID=1

规则分析5

  1. switch (cid) {
  2. case -1:
  3. perror("子进程创建失败");
  4. exit(2);
  5. break;
  6. case 0:
  7. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  8. close(fd[1]);
  9. char message[65535];
  10. int num = read(fd[0], message, 65535);
  11. printf("子进程读入的数据长度是=%d", num);
  12. close(fd[0]);
  13. break;
  14. default:
  15. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  16.  
  17. close(fd[0]);
  18. const long int writesize = 80000;
  19. char writeMsg[writesize];
  20. int i;
  21. for (i = 0; i < writesize; i++) {
  22. writeMsg[i] = 'a';
  23. }
  24. int writenum = write(fd[1], writeMsg, strlen(writeMsg));
  25. printf("父进程写入的数据长度是=%d\n", writenum);
  26. close(fd[1]);
  27. wait(NULL);
  28. break;
  29. }

[root@ Release25$] ps -C processcomm -o pid,ppid,stat,cmd

PID PPID STAT CMD

=>全部进程都以退出

控制台输出

父进程工作PID=7776,PPID=2488

子进程工作PID=7778,PPID=7776

子进程读入的数据长度是=65535

规则分析6

  1. switch (cid) {
  2. case -1:
  3. perror("子进程创建失败");
  4. exit(2);
  5. break;
  6. case 0:
  7. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  8. break;
  9. default:
  10. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  11. const long int writesize=80000;
  12. char writeMsg[writesize];
  13. int i;
  14. for(i=0;i<writesize;i++)
  15. {
  16. writeMsg[i]='a';
  17. }
  18. int writenum=write(fd[1], writeMsg, strlen(writeMsg));
  19. printf("父进程写入的数据长度是=%d\n", writenum);
  20. wait(NULL);
  21. break;
  22. }

父进程工作PID=7309,PPID=2488

子进程工作PID=7314,PPID=7309

[root@ Release24$] ps -C processcomm -o pid,ppid,stat,cmd

PID PPID STAT CMD

7309 2488 S   /root/workspace/processcomm/Release/processcomm

7314 7309 Z    [processcomm]<defunct>

管道代码举例

1.   当发送信息小于管道最大长度

  1. #include<unistd.h>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<sys/types.h>
  5. #include<stdlib.h>
  6. #include<sys/wait.h>
  7.  
  8. int main() {
  9. int fd[2];
  10. pid_t cid;
  11.  
  12. if (pipe(fd) == -1) {
  13. perror("管道创建失败!");
  14. exit(1);
  15. }
  16. cid = fork();
  17. switch (cid) {
  18. case -1:
  19. perror("子进程创建失败");
  20. exit(2);
  21. break;
  22. case 0:
  23. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  24. close(fd[1]);
  25. char message[1000];
  26. int num;
  27. do {
  28.  
  29. num = read(fd[0], message, 1000);
  30. printf("子进程读入的数据长度是=%d\n", num);
  31. } while (num != 0);
  32.  
  33. close(fd[0]);
  34. break;
  35. default:
  36. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  37. close(fd[0]);
  38. const long int writesize = 37;
  39. char writeMsg[writesize];
  40. int i;
  41. for (i = 0; i < writesize-1; i++) {
  42. writeMsg[i] = 'a';
  43. }
  44. writeMsg[writesize-1]='\0';
  45. int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);
  46. printf("父进程写入的数据长度是=%d\n", writenum);
  47. close(fd[1]);
  48. break;
  49. }
  50. return 0;
  51. }

2.   当发送信息大于管道最大长度

此样例主要应该规则6。当发送信息大于管道长度时且写进程在未所有将新数据写入管道中。写进程处于堵塞状态。直到所有数据写入管道

  1. int main() {
  2. int fd[2];
  3. pid_t cid;
  4.  
  5. if (pipe(fd) == -1) {
  6. perror("管道创建失败。");
  7. exit(1);
  8. }
  9. cid = fork();
  10. switch (cid) {
  11. case -1:
  12. perror("子进程创建失败");
  13. exit(2);
  14. break;
  15. case 0:
  16. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  17. close(fd[1]);
  18. char message[1000];
  19. int num;
  20. do {
  21. num = read(fd[0], message, 1000);
  22. printf("子进程读入的数据长度是=%d\n", num);
  23. }while(num!=0);
  24.  
  25. close(fd[0]);
  26. break;
  27. default:
  28. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  29.  
  30. const long int writesize = 80000;
  31. char writeMsg[writesize];
  32. int i;
  33. for (i = 0; i < writesize-1; i++) {
  34. writeMsg[i] = 'a';
  35. }
  36. writeMsg[writesize-1]='\0';
  37. int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);
  38. printf("父进程写入的数据长度是=%d\n", writenum);
  39. close(fd[0]);
  40. close(fd[1]);
  41. break;
  42. }
  43. return 0;
  44. }

3.   写进程多次写入

此例应用规则6,防止多次写入,写入数据长度管道最大长度

  1. int main() {
  2. int fd[2];
  3. pid_t cid;
  4.  
  5. if (pipe(fd) == -1) {
  6. perror("管道创建失败。");
  7. exit(1);
  8. }
  9. cid = fork();
  10. switch (cid) {
  11. case -1:
  12. perror("子进程创建失败");
  13. exit(2);
  14. break;
  15. case 0:
  16. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  17. close(fd[1]);
  18. char message[1000];
  19. int num;
  20. do {
  21. num = read(fd[0], message, 1000);
  22. if (num > 0) {
  23. printf("子进程读入的数据长度是=%d %s\n", num, message);
  24. }
  25.  
  26. } while (num != 0);
  27.  
  28. close(fd[0]);
  29. break;
  30. default:
  31. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  32.  
  33. const long int writesize = 10;
  34. char writeMsg[writesize];
  35. int i;
  36. for (i = 0; i < writesize - 1; i++) {
  37. writeMsg[i] = 'a';
  38. }
  39. writeMsg[writesize - 1] = '\0';
  40. int writenum = write(fd[1], writeMsg, strlen(writeMsg));
  41. printf("父进程写入的数据长度是=%d\n", writenum);
  42.  
  43. char *newmsg = "helloworld";
  44. writenum = write(fd[1], newmsg, strlen(newmsg) + 1);
  45. printf("父进程再次写入的数据长度是=%d\n", writenum);
  46. close(fd[0]);
  47. close(fd[1]);
  48. break;
  49. }
  50. return 0;
  51. }

4.   兄弟间的管道通讯

  1. int main() {
  2. int fd[2];
  3. pid_t cid, did;
  4.  
  5. if (pipe(fd) == -1) {
  6. perror("管道创建失败!");
  7. exit(1);
  8. }
  9. cid = fork();
  10. switch (cid) {
  11. case -1:
  12. perror("兄进程创建失败");
  13. exit(2);
  14. break;
  15. case 0:
  16. printf("兄进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  17. close(fd[1]);
  18. char message[1000];
  19. int num;
  20. do {
  21. num = read(fd[0], message, 1000);
  22. if (num > 0) {
  23. printf("兄进程读入的数据长度是=%d,%s\n", num, message);
  24. }
  25.  
  26. } while (num != 0);
  27.  
  28. close(fd[0]);
  29. break;
  30. default:
  31. did = fork();
  32. if (did == 0) {
  33. printf("弟进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  34.  
  35. const long int writesize = 10;
  36. char writeMsgs[writesize];
  37. int i;
  38. for (i = 0; i < writesize - 1; i++) {
  39. writeMsgs[i] = 'a';
  40. }
  41. writeMsgs[writesize - 1] = '\0';
  42. int writenum = write(fd[1], writeMsgs, strlen(writeMsgs) + 1);
  43. printf("弟进程写入的数据长度是=%d\n", writenum);
  44. close(fd[0]);
  45. close(fd[1]);
  46. } else if (did == -1) {
  47. perror("弟进程创建失败!");
  48. exit(3);
  49.  
  50. }
  51.  
  52. break;
  53. }
  54. return 0;
  55. }

5.   父子双通道管道通讯

  1. int main() {
  2. int fd[2], backfd[2];
  3. pid_t cid;
  4.  
  5. if (pipe(fd) == -1) {
  6. perror("管道创建失败!");
  7. exit(1);
  8. }
  9. if (pipe(backfd) == -1) {
  10. perror("管道创建失败!");
  11. exit(2);
  12. }
  13. cid = fork();
  14. switch (cid) {
  15. case -1:
  16. perror("子进程创建失败");
  17. exit(2);
  18. break;
  19. case 0:
  20. printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  21. close(fd[1]);
  22. char message[10000];
  23. int num;
  24.  
  25. do {
  26.  
  27. num = read(fd[0], message, 10000);
  28. printf("子进程读入的数据长度是=%d\n", num);
  29. } while (num != 0);
  30.  
  31. close(fd[0]);
  32.  
  33. close(backfd[0]);
  34. char *msg1 = "消息返回成功啊!
  35.  
  36. ";
  37. write(backfd[1], msg1, strlen(msg1) + 1);
  38. close(backfd[1]);
  39. break;
  40. default:
  41. printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());
  42.  
  43. const long int writesize = 80000;
  44. char writeMsg[writesize];
  45. int i;
  46. for (i = 0; i < writesize - 1; i++) {
  47. writeMsg[i] = 'a';
  48. }
  49. writeMsg[writesize - 1] = '\0';
  50. int writenum = write(fd[1], writeMsg, strlen(writeMsg) + 1);
  51. printf("父进程写入的数据长度是=%d\n", writenum);
  52. close(fd[0]);
  53. close(fd[1]);
  54. close(backfd[1]);
  55. char msg2[1000];
  56. int num1 = read(backfd[0], msg2, 1000);
  57. printf("返回消息:%s", msg2);
  58. close(backfd[0]);
  59. break;
  60. }
  61. return 0;
  62. }

Linux学习记录--匿名沟通渠道的更多相关文章

  1. linux学习记录(第六章、Linux 的文件权限与目录配置)

    书看的是鸟哥的私房菜,系统用的是centos.被微软坑了N年才发现linux才是王道. 在这里记录些学习的记录.备忘

  2. Linux 学习记录 一(安装、基本文件操作).

         Linux distributions主要分为两大系统,一种是RPM方式安装软件的系统,包括Red Hat,Fedora,SuSE等都是这类:一种则是使用Debian的dpkg方式安装软件的 ...

  3. Linux 学习记录一(安装、基本文件操作).

    Linux 名字的由来,是当时作者将初版的 Linux 发布在网上,供别人下载完善,而那个核心文件夹就叫 Linux,就这么叫着了.而为什么 Linux 的吉祥物是一只企鹅呢?是因为当时大家要发行稳定 ...

  4. Linux学习记录

    ---恢复内容开始--- linux与unix的关系 linux是借鉴了unix设计思想,也称linux位类unix系统. Linux常用命令 1.命令基本格式 命令[选项][参数] 注意:个别命令不 ...

  5. Linux 学习记录

    整理学习Linux操作系统遇到的不理解的概念.逐个进行补充.我们用的版本是CentOs. what's the gcc? what's the yum? what's the wget?

  6. Linux学习记录--命名管道通信

    命名管道通信 什么是命名管道 一个主要的限制是,它是匿名管道的应用还没有名字,因此,只有它可以用于进程间通信的方式与亲缘关系.在命名管道(named pipe或FIFO)提出后,该限制得到了克服.FI ...

  7. Linux 学习记录 20170218

    一.Linux 硬件查看命令     ----/proc 文件系统是一种内核和内核模块用来向进程(process) 发送信息的机制.我们可以从这个文件里获取到系统的相关信息. 1.显卡信息dmesg ...

  8. linux学习记录.1.安装

    最近想了想决定开始学习linux. 在百度了一番后开始了安装,虚拟机VirtualBox,ubuntu. 基于VirtualBox虚拟机安装Ubuntu图文教程: http://blog.csdn.n ...

  9. Linux学习记录(一)

    1.Linux的简介 1.1.Linux的概述 Linux是基于Unix的开源免费的操作系统,由于系统的稳定性和安全性几乎成为程序代码运行的最佳系统环境.Linux是由Linus Torvalds(林 ...

随机推荐

  1. 设计模式(四)原型模式Prototype(创建型)

      设计模式(四)原型模式Prototype(创建型) 1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...

  2. myeclipse自动生成注释

    myeclipse自动生成注释 在使用Eclipse编写Java代码时,自动生成的注释信息都是按照预先设置好的格式生成的,例如其中author的属性值. 我们可以在Eclipse中进行设置自己希望显示 ...

  3. 在cmd窗口中查询android的sqlite3数据库表之步骤

    本文主要是写了一个android程序对sqlite3中数据库的employee表的插入.删除的操作,然后在cmd窗口中用sql命令查询employee表的操作过程. 1.第一步:首先把程序写好. 1. ...

  4. Shell中的if else语句小演示

    安安静静学习小shell,今天看到if else 喽~ 下面这个脚本是判断用户执行脚本的参数,如果是hello的话,就显示how are you 如果什么都没有,就提示输入 如果参数不是hello,就 ...

  5. jquery分页

    //分页插件 /** 2015-12-7 **/ (function($){ var ms = { init:function(obj,args){ return (function(){ ms.fi ...

  6. 工具类CTools实现字符编码转换和获取当前路径

    class CTools { public: CTools(void); public: ~CTools(void); public: static std::string UNICODE_to_UT ...

  7. java--从控制台读入一些数据

    学一些东西应该,学以致用: 现在我开始使用流的办法从控制台读取数据 import java.io.*; public class Demo2{ public static void main(Stri ...

  8. 06-IOSCore - KVC、CoreData

    一. KVC 1. KVC 使用前:黯淡无光 if ([keyPath isEqualToString:@"name"]) { self.labelName.text = self ...

  9. JVM调优总结(七)-典型配置举例1

    以下配置主要针对分代垃圾回收算法而言. 堆大小设置 年轻代的设置很关键 JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理 ...

  10. 华为OJ:计算两个自然时间相加

    按要求一步步做就好 import java.util.Scanner; public class dateAdd { public static void main(String args[]){ S ...