实现c与shell间的双向通信 - Go语言中文社区

实现c与shell间的双向通信


实现c与shell间的双向通信

管道是应用较为广泛的进程间通信的手段,一般来讲,管道是单向的,一个进程负责向管道里写内容,另一个进程负责向管道里读内容。于是我利用了两个管道来实现双向通行。

在这里插入图片描述

  • 具体实现

    • c_conn_shell.h

      //
      // Created by fengjun on 18-9-22.
      //
      
      #ifndef STUDYNET_C_CONN_SHELL_H
      #define STUDYNET_C_CONN_SHELL_H
      
      #include <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      #include <sys/wait.h>
      #include <errno.h>
      #include <fcntl.h>
      
      //存放读写通道句柄与子进程(shell程序)之间的关系
      static pid_t	*ccsChildpid = NULL;
      
      //shell命令的路经
      #define	CCS_SHELL "/bin/sh"
      //能存放的最大句柄数
      #define CCS_MAX_FD 100
      
      /**
       * @brief 执行shell命令,并返回shell程序的的读写句柄
       * @param cmdstring
       * @return 存有两个文件描述符的数组,第一个用于从shell进程读出数据,第二个用于向shell进程写入数据
       */
      int* c_conn_shell(const char *cmdstring);
      
      /**
       * @brief 关闭c与shell程序之间通信的通道
       * @param fd
       * @return 返回子进程终止时的状态
       */
      int c_conn_shell_close(int* fd);
      
      #endif //STUDYNET_C_CONN_SHELL_H
      
    • c_conn_shell.h

      //
      // Created by fengjun on 18-9-22.
      //
      
      #include "c_conn_shell.h"
      
      int* c_conn_shell(const char *cmdstring)
      {
          int		pfdRead[2],pfdWrite[2];
          pid_t	pid;
      
          //第一次进入该函数
          if (ccsChildpid == NULL) {
              //为数组分配内存,并清0
              if ( (ccsChildpid = calloc(CCS_MAX_FD, sizeof(pid_t))) == NULL)
                  return(NULL);
          }
      
          if (pipe(pfdRead) < 0 )
              //pipe()会为errno赋值
              return(NULL);
          else if(pipe(pfdWrite) <0){
              //关闭pfdRead管道,并返回NULL
              close(pfdRead[0]);
              close(pfdRead[1]);
              return(NULL);
          }
      
          if ( (pid = fork()) < 0)
              //fork()会为errno赋值
              return(NULL);
          else if (pid == 0) { //子进程
              close(pfdRead[0]);
              if (pfdRead[1] != STDOUT_FILENO) {
              	//重定向输出
                  dup2(pfdRead[1], STDOUT_FILENO);
                  close(pfdRead[1]);
              }
              close(pfdWrite[1]);
              if (pfdWrite[0] != STDIN_FILENO) {
              	//重定向输入
                  dup2(pfdWrite[0], STDIN_FILENO);
                  close(pfdWrite[0]);
              }
      
              //关闭在ccsChildpid[]中的所有文件描述符
              for (int i = 0; i < CCS_MAX_FD; i++)
                  if (ccsChildpid[ i ] > 0)
                      close(i);
      
              execl(CCS_SHELL, "sh", "-c", cmdstring, (char *) 0);
              _exit(127);
          }
          //父进程
          int* result;
          if ( (result = calloc(2, sizeof(int))) == NULL)
              return(NULL);
      
          close(pfdRead[1]);
          //记录文件描述符的父进程
          ccsChildpid[pfdRead[0]] = pid;
          result[0]=pfdRead[0];
      
          close(pfdWrite[0]);
          //记录文件描述符的父进程
          ccsChildpid[pfdWrite[1]] = pid;
          result[1]=pfdWrite[1];
          return(result);
      }
      
      int c_conn_shell_close(int* fd)
      {
      
          int		stat;
          pid_t	pid;
      
          if (ccsChildpid == NULL)
              //c_conn_shell()还未被调用过
              return(-1);
      
          if ( (pid = ccsChildpid[fd[0]]) == 0 || ccsChildpid[fd[1]] == 0)
              //文件描述符没有被c_conn_shell()打开
              return(-1);
      
          ccsChildpid[fd[0]] = 0;
          ccsChildpid[fd[1]] = 0;
      
          if (close(fd[0]) == EOF || close(fd[1]) == EOF)
              return(-1);
      
          //由于fd是动态分配的,所以需要释放内存
          free(fd);
      
          while (waitpid(pid, &stat, 0) < 0)
              //排除ENTER以外的错误
              if (errno != EINTR)
                  return(-1);	/*  */
                  
          return(stat);
      }
      

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_36291381/article/details/82823075
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢