社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
管道是应用较为广泛的进程间通信的手段,一般来讲,管道是单向的,一个进程负责向管道里写内容,另一个进程负责向管道里读内容。于是我利用了两个管道来实现双向通行。
具体实现
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);
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!