實現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); }
-