Linux 进程间通信 管道系列: 匿名和定名管道,自定义shell当中下令行管道的 ...

打印 上一主题 下一主题

主题 507|帖子 507|积分 1521

一.进程间通信的介绍

1.为什么要进程进程间通信?

由于有些情况下需要进程完成以下使命:

而我们知道进程之间是不能举行"数据"的直接传递的,由于进程具有独立性
因此才有了我们今天要评论的进程间通信
2.什么是进程间通信

普通点讲,进程间通信就是一个进程能够把自己的数据交给另一个进程
进程间进程通信就是举行数据的交互,那么数据存放在那边呢?
下面我们来分析一下

因此,关于进程间通信的一个非非非非非非常重要的结论就得出了:
   进程间通信的本质是让差别的进程,看到同一份资源(一般都是要由OS提供)
  3.进程间通信的详细做法

由于OS提供的"数据存放的空间"有着你差别的样式,就决定了进程间通信有着差别的通信方式

二.管道

管道的本质就是一个内存级文件,不存储在磁盘上,只存储在内存当中
1.从文件的角度理解什么是管道?


创建子进程之后log.txt的struct file对象的引用计数++
此时父子进程都对log.txt这个文件同时具有读写权限
也就是说父子进程看到了同一份资源(log.txt),这就是进程间通信
此时假如子进程对log.txt举行写入,父进程对log.txt举行读取
这不就完成了进程间通信了吗?
因此,这种
   基于文件,让差别进程看到同一份资源的方式,就叫做管道!
  假如让父子进程同时对log.txt既有读权限,又有写权限,那不就容易发生混乱吗?
因此设计管道的工程师规定:
   管道只能被设计为单向通信!
  那么我们如何把刚才的情况改为只能举行单向通信呢?
比方说我们要求父进程作为读端,子进程作为写端
只需要关闭父进程的’w’权限和子进程的’r’权限即可
log.txt的struct file对象的引用计数–
只有当引用计数减为0时,才会释放该struct file对象和其内核缓冲区
此时,父子进程的通信方式就叫做管道!!
回想一下,刚才我们是如何让差别的进程看到同一份资源的呢?
   通过创建子进程,子进程会继承父进程的相干属性信息
  子进程继承了父进程的相干信息,子进程的子进程也会继承子进程的相干信息
那么子进程的子进程不就也能跟父进程举行进程间通信了吗?
是的,因此进程之间只要具有血缘关系,那么就可以利用管道来举行进程间通信
而假如没有血缘关系,那么就无法利用管道来举行进程间通信了
三.匿名管道

假如此时我们想要让两个进程之间举行通信,但是不想在磁盘当中创建单独的文件,怎么办呢?
此时就可以使用匿名管道了
匿名管道:只能让具有血缘关系的进程之间举行进程间通信(常用于父子进程)
(先人跟后代可以,兄弟之间也可以哦)
如何利用呢?

pipe这个函数就是用来创建匿名管道的,传入的参数是一个数组,是一个输出型参数
实行该函数后,会得到2个fd,分别存储在pipefd[0]和pipefd[1]的位置
pipefd[0]存储的是负责r(读)的fd,pipefd[1]存储的是负责w(写)的fd
pipe所创建的匿名管道是一个内存级的文件,并不存在于磁盘当中!!
创建成功返回值为0,创建失败返回值小于0
1.验证代码

下面我们来写一个验证代码

这份代码的含义是:
1.创建管道
2.创建子进程
3.子进程死循环向管道当中写入数据
4.父进程死循环从管道当中读取数据
然后我们编译生成可实行程序,开始运行

至此我们验证完毕
2.四种情况

颠末刚才的演示,我们知道父子进程是如何通过管道来举行通信的了
但是还是不敷细节,由于有些情况没有涉及到,下面我们来一一看看这4种情况吧

为了方便演示,我们改一下代码,让子进程发送消息时每次少发一些
不发急,我们一一分析
1.写端不写,且不退




2.读端不读,且不退




补充一点:

PIPE_BUF:管道的缓存大小是4096字节
   当要写入的数据量不大于PIPE_BUF时,Linux将包管写入的原子性
当要写入的数据量大于PIPE_BUF时,Linux将不再包管写入的原子性
  关于原子性我们以后会还会见到的

3.写端不写,退了





4.读端不读,退了


其实发送的是13号信号:
SIGPIPE
验证:


5.小小总结


3.五种特性


4.理解下令行管道

我们之前在Linux常见指令2当中介绍过下令行管道的使用

而今天我们学习了管道之后,我们再回过头来重新认识一下下令行管道
  1. ps ajx | head -1 && ps ajx | grep 可执行程序名字 | grep -v grep
复制代码
还记得我们的监控脚本吗?
其实它就是一个下令行管道的典型应用

四.定名管道

匿名管道挺好的,只不过只能由具有血缘关系的进程才气够使用,还是有些局限性的
能不能让没有血缘关系的进程之间也能使用管道来通信呢?
是可以的,不过需要使用我们接下来要介绍的定名管道
1.理论

1.回首匿名管道的原理


2.定名管道理论



2.系统调用接口的介绍与使用

1.介绍

跟匿名管道一样,这件事变OS不放心让用户完成,也是为了给用户一个良好的使用体验,因此OS提供了系统调用接口
mkfifo

2.使用

我们知道|是下令行当中的匿名管道,阐明Linux支持在下令行当中创建匿名管道,那么定名管道呢?
假如不允许的话,Linux是不是就有点偏心了啊
Linux也允许在下令行当中使用mkfifo来创建定名文件
曾记否:我们之前在介绍Linux下的文件类型的时间见过这个管道文件哦

今天我们想说的是:创建了一个定名管道之后,就不能再创建同名的定名管道了

因此我们在创建了定名管道之后,当本次客户端和服务端通信结束之后,为了让下一次对应的代码还能正常运行(也就是创建定名管道成功)
而且肯定是客户端先退出,所以我们要在服务端退出时将这个定名管道删掉
如何删呢?总不能进程程序更换实行个rm -f xxx定名管道吧,那也太挫了吧
OS肯定要提供系统调用接口


同样的unlink也是一个指令哦
介绍完我们需要使用的新增的系统调用接口之后,下面我们来搞代码啦
3.代码编写


这里unlink,read,write,open等等都要判断是否成功,这里为了让代码更加简洁,就没怎么判断,各人可以加上,返回错误码是真的难受…
还是非常香
1.Common.hpp

定名管道是不是只有一份呢?
不是,可以同时有许多份,OS要不要管理,要
如何管理?先描述,在组织
走起

2.pipeServer.cpp


注意:
定名管道创建之后
假如只有读端被打开了,写端还没有被打开,那么读端会壅闭在open函数当中
假如只有写端被打开了,读端还没有被打开,那么写端会壅闭在open函数当中
3.pipeClient.cpp


4.makefile

由于要生成2个可实行程序,因此需要用一个伪目的
(固然你make xxx两次也可以,主要是不优雅)

4.动图演示

此时就能够任意玩了

固然你要是想换一下读写端的话,两个人约定一些暗号等等的信息,输入之后就先暂时退出,然后各自换一种权限打开该文件等等,
这一点上面比匿名管道好玩总之,你想怎么玩就怎么写
随意~
五.自定义shell当中添加下令行管道的功能

1.前言

前言 : 有些内建下令简直可以跟下令行管道一起使用,比方echo,不过某些内建下令无法跟下令行管道一起使用:比如cd
下令行管道可以跟重定向>>,>,<一起使用
拿出我们实现完重定向的shell,(我今天是由自己写了一遍,所以跟上一次的有些差别,但功能是一样的,各人知道能这么玩就行,有空的时间可以自己玩一下)
(另有就是谁人echo $?返回最近一次错误码,由于最近刚学了非常,所以看到这种错误码就满身难受,所以没有搞这个,不过不妨碍我们今天要实现的重定向)
这是一个cpp文件(由于假如用C添加下令行管道[太麻烦了,连个次序表都没有]…写C++写惯了,不想用C…)
为了方便实现,我们把main函数中的代码拿出去了两部门
代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/wait.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <ctype.h>
  9. #include <fcntl.h>
  10. #include <vector>
  11. #include <iostream>
  12. #define NoneRedir 0
  13. #define OutputRedir 1
  14. #define InputRedir 2
  15. #define AppendRedir 3
  16. using namespace std;
  17. int lastcode=0;//上一次进程退出时的退出码
  18. int redir=NoneRedir;
  19. char* filename=NULL;
  20. char cwd[1024]={'\0'};
  21. char env[1024][1024]={'\0'};
  22. int my_index=0;
  23. //将字符串s按照空格作为分割符拆分后添加到vs当中(不过: 空格可能会连续出现)
  24. void CommandLineSplit(char* command,char* commandV[])
  25. {
  26.     char* s=strtok(command," ");
  27.     commandV[0]=s;
  28.     int i=1;
  29.     while(commandV[i++]=strtok(NULL," ")){}
  30. }
  31. #define SkipSpace(pos) do{while(isspace(*pos)){pos++;}}while(0)
  32. void CheckRedir(char* command)
  33. {
  34.     int len=strlen(command);
  35.     char* pos;
  36.     for(int i=len-1;i>=0;)
  37.     {
  38.         if(command[i]=='>')
  39.         {
  40.             if(i>0 && command[i-1]=='>')//追加
  41.             {
  42.                 redir=AppendRedir;
  43.                 command[i-1]='\0';
  44.             }
  45.             else//输出
  46.             {
  47.                 redir=OutputRedir;
  48.                 command[i]='\0';
  49.             }
  50.             pos=command+i+1;
  51.             SkipSpace(pos);
  52.             filename=pos;
  53.             break;
  54.         }
  55.         else if(command[i]=='<')//输入
  56.         {
  57.             redir=InputRedir;
  58.             command[i]='\0';
  59.             pos=command+i+1;
  60.             SkipSpace(pos);
  61.             filename=pos;
  62.             break;
  63.         }
  64.         else
  65.         {
  66.             i--;
  67.         }
  68.     }
  69. }
  70. void Exec(char* commandV[])
  71. {
  72.     pid_t id=fork();
  73.     if(id==0)
  74.     {
  75.         if(redir==InputRedir)
  76.         {
  77.             int fd=open(filename,O_RDONLY);
  78.             dup2(fd,0);
  79.         }
  80.         else if(redir==OutputRedir)
  81.         {
  82.             int fd=open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666);
  83.             dup2(fd,1);
  84.         }
  85.         else if(redir==AppendRedir)
  86.         {
  87.             int fd=open(filename,O_WRONLY | O_CREAT | O_APPEND,0666);
  88.             dup2(fd,1);
  89.         }
  90.         execvp(commandV[0],commandV);
  91.     }
  92.     wait(NULL);
  93. }
  94. void cd(char* path)
  95. {
  96.     chdir(path);
  97.     char tmp[1024]={'\0'};
  98.     getcwd(tmp,sizeof(tmp));
  99.     sprintf(cwd,"PWD=%s",tmp);
  100.     putenv(cwd);
  101. }
  102. void Export(char* s)
  103. {
  104.     strcpy(env[my_index],s);
  105.     putenv(env[my_index++]);
  106. }
  107. int echo(char* commandV[])
  108. {
  109.         //1.echo后面什么都没有,相当于'\n'
  110.         if(commandV[1]==NULL)
  111.         {
  112.             printf("\n");
  113.             lastcode=0;
  114.             return 1;
  115.         }
  116.         //2.echo $?  echo $PWD echo $
  117.         char* cmd=commandV[1];
  118.         int len=strlen(cmd);
  119.         if(cmd[0]=='$' && len>1)
  120.         {
  121.             //echo $?
  122.             if(cmd[1]=='?')
  123.             {
  124.                 printf("%d\n",lastcode);
  125.                 lastcode=0;
  126.             }
  127.             //echo $PWD
  128.             else
  129.             {
  130.                 char* tmp=cmd+1;
  131.                 const char* env=getenv(tmp);
  132.                 //找不到该环境变量,打印'\n',退出码依旧为0
  133.                 if(env==NULL)
  134.                 {
  135.                     printf("\n");
  136.                 }
  137.                 else
  138.                 {
  139.                     printf("%s\n",env);
  140.                 }
  141.                 lastcode=0;
  142.             }
  143.         }
  144.         else
  145.         {
  146.             if(cmd[0]=='"' && cmd[len-1]=='"')
  147.             {
  148.                 cmd[len-1]='\0';
  149.                 printf("%s\n",cmd+1);
  150.             }
  151.             else
  152.                 printf("%s\n",cmd);
  153.         }
  154.         return 1;
  155. }
  156. int doBulidIn(char* commandV[])
  157. {
  158.     int ret=0;
  159.     if(strcmp(commandV[0],"cd")==0)
  160.     {
  161.         cd(commandV[1]);
  162.         ret=1;
  163.     }
  164.     else if(strcmp(commandV[0],"export")==0)
  165.     {
  166.         Export(commandV[1]);
  167.         ret=1;
  168.     }
  169.     else if(strcmp(commandV[0],"echo")==0)
  170.     {
  171.         echo(commandV);
  172.         ret=1;
  173.     }
  174.     return ret;
  175. }
  176. //打印提示符和修正redir,filename的函数
  177. void step1()
  178. {
  179.     redir=NoneRedir;
  180.     filename=NULL;
  181.     //1.打印提示符wzs@VM-16-10-ubuntu:~/ubuntucode/shell$
  182.     printf("%s@VM-16-10-ubuntu:%s$ ",getenv("USER"),getenv("PWD"));
  183. }
  184. //具体执行指令的函数
  185. void step3(char* command)
  186. {
  187.     //3.检查重定向
  188.     CheckRedir(command);
  189.     //4.解析字符串
  190.     char* commandV[1024]={NULL};
  191.     CommandLineSplit(command,commandV);
  192.     //5.分析内建命令
  193.     int ret=doBulidIn(commandV);
  194.     if(ret==0)
  195.     {
  196.         //6.进程程序替换
  197.         Exec(commandV);
  198.     }
  199. }
  200. int main()
  201. {
  202.     while(1)
  203.     {
  204.         step1();
  205.         char command[1024]={'\0'};
  206.         fgets(command,sizeof(command),stdin);
  207.         int len=strlen(command);
  208.         command[len-1]='\0';
  209.         step3(command);
  210.     }
  211.     return 0;
  212. }
复制代码
2.思绪

1.如何创建管道与进程


因此,我们只需要边创建管道,边创建进程,(最后一个进程单独创建)
而且用vector<pair<int,int>>存储全部的管道的读写端方便后续管道对其举行关闭
(由于管道的特点是读/写端没有全都退出,另一端就会一直壅闭等候,假如不关闭读写端的话父进程接纳时就必须要逆序接纳)
又由于我们要让父进程接纳子进程,所以在用一个vector<int>存储全部的子进程pid,后续还要waitpid接纳他们呢
2.预处置惩罚

在检查是否需要重定向之前,我们需要先检查整个字符串有多少个’|‘下令行管道,而且
[1]用一个vector<int>生存它们的位置,而且将对应位置改为’\0’,方便后续把每一块指令传递给子进程去处置惩罚
[2]由于第一个指令左侧没有’|',所以我们在初始化vector<int>的时间,可以先存上一个-1,然后分配使命时就好分配了
3.实现

只有刚才的这两步,搞清楚这两点之后代码就能够很好的写出来了

4.演示


5.代码

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/wait.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <ctype.h>
  9. #include <fcntl.h>
  10. #include <vector>
  11. #include <iostream>
  12. #define NoneRedir 0
  13. #define OutputRedir 1
  14. #define InputRedir 2
  15. #define AppendRedir 3
  16. using namespace std;
  17. int lastcode=0;//上一次进程退出时的退出码
  18. int redir=NoneRedir;
  19. char* filename=NULL;
  20. char cwd[1024]={'\0'};
  21. char env[1024][1024]={'\0'};
  22. int my_index=0;
  23. //将字符串s按照空格作为分割符拆分后添加到vs当中(不过: 空格可能会连续出现)
  24. void CommandLineSplit(char* command,char* commandV[])
  25. {
  26.     char* s=strtok(command," ");
  27.     commandV[0]=s;
  28.     int i=1;
  29.     while(commandV[i++]=strtok(NULL," ")){}
  30. }
  31. #define SkipSpace(pos) do{while(isspace(*pos)){pos++;}}while(0)
  32. void CheckRedir(char* command)
  33. {
  34.     int len=strlen(command);
  35.     char* pos;
  36.     for(int i=len-1;i>=0;)
  37.     {
  38.         if(command[i]=='>')
  39.         {
  40.             if(i>0 && command[i-1]=='>')//追加
  41.             {
  42.                 redir=AppendRedir;
  43.                 command[i-1]='\0';
  44.             }
  45.             else//输出
  46.             {
  47.                 redir=OutputRedir;
  48.                 command[i]='\0';
  49.             }
  50.             pos=command+i+1;
  51.             SkipSpace(pos);
  52.             filename=pos;
  53.             break;
  54.         }
  55.         else if(command[i]=='<')//输入
  56.         {
  57.             redir=InputRedir;
  58.             command[i]='\0';
  59.             pos=command+i+1;
  60.             SkipSpace(pos);
  61.             filename=pos;
  62.             break;
  63.         }
  64.         else
  65.         {
  66.             i--;
  67.         }
  68.     }
  69. }
  70. void Exec(char* commandV[])
  71. {
  72.     pid_t id=fork();
  73.     if(id==0)
  74.     {
  75.         if(redir==InputRedir)
  76.         {
  77.             int fd=open(filename,O_RDONLY);
  78.             dup2(fd,0);
  79.         }
  80.         else if(redir==OutputRedir)
  81.         {
  82.             int fd=open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666);
  83.             dup2(fd,1);
  84.         }
  85.         else if(redir==AppendRedir)
  86.         {
  87.             int fd=open(filename,O_WRONLY | O_CREAT | O_APPEND,0666);
  88.             dup2(fd,1);
  89.         }
  90.         execvp(commandV[0],commandV);
  91.     }
  92.     wait(NULL);
  93. }
  94. void cd(char* path)
  95. {
  96.     chdir(path);
  97.     char tmp[1024]={'\0'};
  98.     getcwd(tmp,sizeof(tmp));
  99.     sprintf(cwd,"PWD=%s",tmp);
  100.     putenv(cwd);
  101. }
  102. void Export(char* s)
  103. {
  104.     strcpy(env[my_index],s);
  105.     putenv(env[my_index++]);
  106. }
  107. int echo(char* commandV[])
  108. {
  109.         //1.echo后面什么都没有,相当于'\n'
  110.         if(commandV[1]==NULL)
  111.         {
  112.             printf("\n");
  113.             lastcode=0;
  114.             return 1;
  115.         }
  116.         //2.echo $?  echo $PWD echo $
  117.         char* cmd=commandV[1];
  118.         int len=strlen(cmd);
  119.         if(cmd[0]=='$' && len>1)
  120.         {
  121.             //echo $?
  122.             if(cmd[1]=='?')
  123.             {
  124.                 printf("%d\n",lastcode);
  125.                 lastcode=0;
  126.             }
  127.             //echo $PWD
  128.             else
  129.             {
  130.                 char* tmp=cmd+1;
  131.                 const char* env=getenv(tmp);
  132.                 //找不到该环境变量,打印'\n',退出码依旧为0
  133.                 if(env==NULL)
  134.                 {
  135.                     printf("\n");
  136.                 }
  137.                 else
  138.                 {
  139.                     printf("%s\n",env);
  140.                 }
  141.                 lastcode=0;
  142.             }
  143.         }
  144.         else
  145.         {
  146.             if(cmd[0]=='"' && cmd[len-1]=='"')
  147.             {
  148.                 cmd[len-1]='\0';
  149.                 printf("%s\n",cmd+1);
  150.             }
  151.             else
  152.                 printf("%s\n",cmd);
  153.         }
  154.         return 1;
  155. }
  156. int doBulidIn(char* commandV[])
  157. {
  158.     int ret=0;
  159.     if(strcmp(commandV[0],"cd")==0)
  160.     {
  161.         cd(commandV[1]);
  162.         ret=1;
  163.     }
  164.     else if(strcmp(commandV[0],"export")==0)
  165.     {
  166.         Export(commandV[1]);
  167.         ret=1;
  168.     }
  169.     else if(strcmp(commandV[0],"echo")==0)
  170.     {
  171.         echo(commandV);
  172.         ret=1;
  173.     }
  174.     return ret;
  175. }
  176. void step1()
  177. {
  178.     redir=NoneRedir;
  179.     filename=NULL;
  180.     //1.打印提示符wzs@VM-16-10-ubuntu:~/ubuntucode/shell$
  181.     printf("%s@VM-16-10-ubuntu:%s$ ",getenv("USER"),getenv("PWD"));
  182. }
  183. void step3(char* command)
  184. {
  185.     //3.检查重定向
  186.     CheckRedir(command);
  187.     //4.解析字符串
  188.     char* commandV[1024]={NULL};
  189.     CommandLineSplit(command,commandV);
  190.     //5.分析内建命令
  191.     int ret=doBulidIn(commandV);
  192.     if(ret==0)
  193.     {
  194.         //6.进程程序替换
  195.         Exec(commandV);
  196.     }
  197. }
  198. int CheckPipe(char* command,vector<int>& v)//返回管道个数,并且把|的位置填到数组当中
  199. {
  200.     int len=strlen(command);
  201.     for(int i=0;i<len;i++)
  202.     {
  203.         if(command[i]=='|')
  204.         {
  205.             v.push_back(i);
  206.             command[i]='\0';//直接截断
  207.         }
  208.     }
  209.     return v.size();
  210. }
  211. void Execpipe(char* command)
  212. {
  213.     vector<int> pos(1,-1);//为了后续分割方便
  214.     int sz=CheckPipe(command,pos);
  215.     if(sz==1)
  216.     {
  217.         step3(command);
  218.         return;
  219.     }
  220.     vector<int> child_id;
  221.     vector<pair<int,int>> v;//v[i].first:i号管道的读 second:写
  222.     for(int i=0;i<sz-1;i++)//创建sz个进程,sz-1个管道
  223.     {
  224.         int pipefd[2];
  225.         int n=pipe(pipefd);
  226.         pid_t id=fork();
  227.         if(id==0)
  228.         {
  229.             close(pipefd[0]);//关闭当前管道的读
  230.             int prev_fd_sz=v.size();
  231.             for(int j=0;j<prev_fd_sz;j++)
  232.             {
  233.                 if(j<prev_fd_sz-1)
  234.                 {
  235.                     //把前面打开的读都关上(除了最近的那一个管道)
  236.                     close(v[j].first);
  237.                 }
  238.                 //把前面打开的管道的写都关上
  239.                 close(v[j].second);
  240.             }
  241.             dup2(pipefd[1],1);//当前管道的写重定向到我的1
  242.             if(!v.empty()) dup2(v.back().first,0);//上一个管道的读重定向到我的0
  243.             step3(command+pos[i]+1);
  244.             exit(0);
  245.         }
  246.         else
  247.         {
  248.             v.push_back({pipefd[0],pipefd[1]});
  249.             child_id.push_back(id);
  250.         }
  251.     }
  252.     //最后一个进程:
  253.     pid_t id=fork();
  254.     if(id==0)
  255.     {
  256.         int prev_fd_sz=v.size();
  257.         for(int j=0;j<prev_fd_sz;j++)
  258.         {
  259.             if(j<prev_fd_sz-1)
  260.             {
  261.                 //把前面打开的读都关上(除了最近的那一个管道)
  262.                 close(v[j].first);
  263.             }
  264.             //把前面打开的管道的写都关上
  265.             close(v[j].second);
  266.         }
  267.         dup2(v.back().first,0);
  268.         step3(command+pos[sz-1]+1);
  269.         exit(0);
  270.     }
  271.     child_id.push_back(id);
  272.     for(auto& e:v)
  273.     {
  274.         //最后的时候父亲关闭所有的读写端
  275.         close(e.first);close(e.second);
  276.     }
  277.     for(auto& e:child_id)
  278.     {
  279.         pid_t rid=waitpid(e,nullptr,0);
  280.         if(rid>0) cout<<"wait success, pid: "<<rid<<endl;
  281.     }
  282. }
  283. int main()
  284. {
  285.     while(1)
  286.     {
  287.         step1();
  288.         char command[1024]={'\0'};
  289.         fgets(command,sizeof(command),stdin);
  290.         int len=strlen(command);
  291.         command[len-1]='\0';
  292.         Execpipe(command);
  293.     }
  294.     return 0;
  295. }
复制代码
  以上就是Linux 进程间通信 管道系列: 匿名和定名管道,自定义shell当中下令行管道的模拟实现的全部内容,希望能对各人有所资助!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表