Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 同步读写_C++_C - Fatal编程技术网

C++ 同步读写

C++ 同步读写,c++,c,C++,C,是否可以读取和写入popen返回的文件描述符。我想通过C控制一个交互式进程。如果popen无法实现这一点,有什么办法吗?只能在读或写模式下打开管道,不能同时在读或写模式下打开管道。查看线程以找到解决方法。您不能使用popen来使用双向管道 事实上,一些操作系统不支持双向管道,在这种情况下,套接字对(socketpair)是唯一的方法。使用forkpty(这是非标准的,但API非常好,如果没有,您可以随时加入自己的实现)和exec要在子进程中与之通信的程序 或者,如果tty语义不符合您的喜好,您可

是否可以读取和写入popen返回的文件描述符。我想通过C控制一个交互式进程。如果popen无法实现这一点,有什么办法吗?

只能在读或写模式下打开管道,不能同时在读或写模式下打开管道。查看线程以找到解决方法。

您不能使用
popen
来使用双向管道

事实上,一些操作系统不支持双向管道,在这种情况下,套接字对(
socketpair
)是唯一的方法。

使用
forkpty
(这是非标准的,但API非常好,如果没有,您可以随时加入自己的实现)和
exec
要在子进程中与之通信的程序


或者,如果tty语义不符合您的喜好,您可以编写类似于
forkpty
的东西,但可以使用两个管道,每个通信方向一个,或者使用
socketpair
通过unix套接字与外部程序通信。

您需要一种通常称为popen2的东西。下面是一个无错误检查(通过web搜索找到,而不是我的代码):

//http://media.unpythonic.net/emergent-files/01108826729/popen2.c
#包括
#包括
#包括
#包括
#包括
#包括“popen2.h”
int popen2(const char*cmdline,struct popen2*childinfo){
pid_t p;
内部管道标准[2],管道标准[2];
if(pipe(pipe_stdin))返回-1;
if(pipe(pipe_stdout))返回-1;
//printf(“管道标准[0]=%d,管道标准[1]=%d\n”,管道标准[0],管道标准[1]);
//printf(“管道标准[0]=%d,管道标准[1]=%d\n”,管道标准[0],管道标准[1]);
p=fork();
如果(p<0)返回p;/*Fork失败*/
如果(p==0){/*child*/
关闭(管道标准[1]);
dup2(管道标准[0],0);
关闭(管道出口[0]);
dup2(管道标准件[1],1);
execl(“/bin/sh”、“sh”、“-c”、cmdline、NULL);
出口(99);
}
childinfo->child_pid=p;
childinfo->to_child=pipe_stdin[1];
childinfo->from_child=pipe_stdout[0];
关闭(管道标准[0]);
关闭(管道[1]);
返回0;
}
//#定义测试
#ifdef测试
内部主(空){
char-buf[1000];
结构popen2;
popen2(“tra-za-z”和kid);
写(kid.to_child,“testing\n”,8);
接近(儿童对儿童);
memset(buf,0,1000);
阅读(儿童从儿童,buf,1000);
printf(“kill(%d,0)->%d\n”,kid.child\u pid,kill(kid.child\u pid,0));
printf(“来自子项:%s”,buf);
printf(“waitpid()->%d\n”,waitpid(kid.child_-pid,NULL,0));
printf(“kill(%d,0)->%d\n”,kid.child\u pid,kill(kid.child\u pid,0));
返回0;
}
#恩迪夫

如前所述,popen朝一个方向工作。如果需要读写,可以使用pipe()创建管道,通过fork()和exec函数跨越新进程,然后使用dup2()重定向其输入和输出。无论如何,我更喜欢exec而不是popen,因为它可以让您更好地控制流程(例如,您知道它的pid)

编辑:

如注释所示,管道只能在一个方向上使用。因此,您必须为读取和写入创建单独的管道。由于之前发布的示例是错误的,我将其删除并创建了一个新的、正确的示例:

#include<unistd.h>
#include<sys/wait.h>
#include<sys/prctl.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>

int main(int argc, char** argv)
{
  pid_t pid = 0;
  int inpipefd[2];
  int outpipefd[2];
  char buf[256];
  char msg[256];
  int status;

  pipe(inpipefd);
  pipe(outpipefd);
  pid = fork();
  if (pid == 0)
  {
    // Child
    dup2(outpipefd[0], STDIN_FILENO);
    dup2(inpipefd[1], STDOUT_FILENO);
    dup2(inpipefd[1], STDERR_FILENO);

    //ask kernel to deliver SIGTERM in case the parent dies
    prctl(PR_SET_PDEATHSIG, SIGTERM);

    //replace tee with your process
    execl("/usr/bin/tee", "tee", (char*) NULL);
    // Nothing below this line should be executed by child process. If so, 
    // it means that the execl function wasn't successfull, so lets exit:
    exit(1);
  }
  // The code below will be executed only by parent. You can write and read
  // from the child using pipefd descriptors, and you can send signals to 
  // the process using its pid by kill() function. If the child process will
  // exit unexpectedly, the parent process will obtain SIGCHLD signal that
  // can be handled (e.g. you can respawn the child process).

  //close unused pipe ends
  close(outpipefd[0]);
  close(inpipefd[1]);

  // Now, you can write to outpipefd[1] and read from inpipefd[0] :  
  while(1)
  {
    printf("Enter message to send\n");
    scanf("%s", msg);
    if(strcmp(msg, "exit") == 0) break;

    write(outpipefd[1], msg, strlen(msg));
    read(inpipefd[0], buf, 256);

    printf("Received answer: %s\n", buf);
  }

  kill(pid, SIGKILL); //send SIGKILL signal to the child process
  waitpid(pid, &status, 0);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv)
{
pid_t pid=0;
int-inpipefd[2];
int outpipefd[2];
char-buf[256];
char-msg[256];
智力状态;
管道(inpipefd);
管道(输出管道FD);
pid=fork();
如果(pid==0)
{
//孩子
dup2(输出管FD[0],标准文件号);
dup2(inpipefd[1],标准文件号);
dup2(inpipefd[1],标准文件号);
//要求内核交付SIGTERM,以防父级死亡
prctl(PR_SET_PDEATHSIG,SIGTERM);
//用您的流程替换tee
execl(“/usr/bin/tee”,“tee”,“char*)NULL);
//子进程不应执行此行以下的任何内容。如果是,
//这意味着execl函数未成功,因此让我们退出:
出口(1);
}
//下面的代码将仅由父级执行。您可以写入和读取
//使用pipefd描述符从子系统发送,您可以向
//进程使用其pid by kill()函数。如果子进程
//意外退出,父进程将获得SIGCHLD信号
//可以处理(例如,您可以重新启动子进程)。
//关闭未使用的管端
关闭(outpipefd[0]);
关闭(inpipefd[1]);
//现在,您可以写入outpipefd[1]并从inpipefd[0]读取:
而(1)
{
printf(“输入要发送的消息”);
scanf(“%s”,msg);
如果(strcmp(msg,“退出”)==0)中断;
写入(outpipefd[1],msg,strlen(msg));
读取(inpipefd[0],buf,256);
printf(“收到的答复:%s\n”,buf);
}
kill(pid,SIGKILL);//向子进程发送SIGKILL信号
waitpid(pid和status,0);
}
popen()和friends不提供双向通信的原因是,由于子进程中存在缓冲,因此容易发生死锁。答案中讨论的所有临时管道和
socketpair()
解决方案都面临相同的问题

在UNIX下,大多数命令不能被信任读取一行并立即处理和打印,除非它们的标准输出是tty。原因是,默认情况下,stdio在用户空间中缓冲输出,并延迟
write()
系统调用,直到缓冲区已满或stdio流关闭(通常是因为程序或脚本在看到输入上的EOF后即将退出)。如果您通过管道写入这样一个程序的stdin,现在等待来自该程序stdout的应答(不关闭入口管道),那么应答将被卡在stdio缓冲区中,并且永远不会出来-这是一个死锁

您可以通过使用伪tty与一些面向行的程序(例如
grep
)对话来欺骗它们,使其不进行缓冲;看一看。但在一般情况下,您必须重新运行
#include<unistd.h>
#include<sys/wait.h>
#include<sys/prctl.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>

int main(int argc, char** argv)
{
  pid_t pid = 0;
  int inpipefd[2];
  int outpipefd[2];
  char buf[256];
  char msg[256];
  int status;

  pipe(inpipefd);
  pipe(outpipefd);
  pid = fork();
  if (pid == 0)
  {
    // Child
    dup2(outpipefd[0], STDIN_FILENO);
    dup2(inpipefd[1], STDOUT_FILENO);
    dup2(inpipefd[1], STDERR_FILENO);

    //ask kernel to deliver SIGTERM in case the parent dies
    prctl(PR_SET_PDEATHSIG, SIGTERM);

    //replace tee with your process
    execl("/usr/bin/tee", "tee", (char*) NULL);
    // Nothing below this line should be executed by child process. If so, 
    // it means that the execl function wasn't successfull, so lets exit:
    exit(1);
  }
  // The code below will be executed only by parent. You can write and read
  // from the child using pipefd descriptors, and you can send signals to 
  // the process using its pid by kill() function. If the child process will
  // exit unexpectedly, the parent process will obtain SIGCHLD signal that
  // can be handled (e.g. you can respawn the child process).

  //close unused pipe ends
  close(outpipefd[0]);
  close(inpipefd[1]);

  // Now, you can write to outpipefd[1] and read from inpipefd[0] :  
  while(1)
  {
    printf("Enter message to send\n");
    scanf("%s", msg);
    if(strcmp(msg, "exit") == 0) break;

    write(outpipefd[1], msg, strlen(msg));
    read(inpipefd[0], buf, 256);

    printf("Received answer: %s\n", buf);
  }

  kill(pid, SIGKILL); //send SIGKILL signal to the child process
  waitpid(pid, &status, 0);
}
static bool
start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
{
    int p1[2], p2[2];

    if (!pid || !infd || !outfd)
        return false;

    if (pipe(p1) == -1)
        goto err_pipe1;
    if (pipe(p2) == -1)
        goto err_pipe2;
    if ((*pid = fork()) == -1)
        goto err_fork;

    if (*pid) {
        /* Parent process. */
        *infd = p1[1];
        *outfd = p2[0];
        close(p1[0]);
        close(p2[1]);
        return true;
    } else {
        /* Child process. */
        dup2(p1[0], 0);
        dup2(p2[1], 1);
        close(p1[0]);
        close(p1[1]);
        close(p2[0]);
        close(p2[1]);
        execvp(*command, command);
        /* Error occured. */
        fprintf(stderr, "error running %s: %s", *command, strerror(errno));
        abort();
    }

err_fork:
    close(p2[1]);
    close(p2[0]);
err_pipe2:
    close(p1[1]);
    close(p1[0]);
err_pipe1:
    return false;
}