实现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); }
-