RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 566796
Accepted
AccumPlus
AccumPlus
Asked:2020-09-16 14:23:31 +0000 UTC2020-09-16 14:23:31 +0000 UTC 2020-09-16 14:23:31 +0000 UTC

在进程之间传递和接收数据(C++ 和 Python)

  • 772

我有一个用 C++ 编写的程序。有一个用 Python 编写的脚本(使用哪种语言并不重要)。有必要将这些程序的进程之间的数据传输正式化。具有 GNU/Linux 内核的操作系统。

我看到了不同的选项,但基本上 Python 始终充当启动 C++ 程序进程的启动应用程序。C++ 进程运行 Python 脚本需要相反的过程。

希望该方法是通用的,即可以用另一种语言编写脚本并使用相同的方法与其交换数据。

c++
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. avp
    2020-09-20T23:31:07Z2020-09-20T23:31:07Z

    如果你想在 Linux 中与 C / C ++ 程序的脚本交换消息,就像你坐在终端前一样(即如果脚本读取标准输入并写入标准输出),那么你可以使用这个功能

    #include <stdio.h>
    #include <stdlib.h>
    #include <termios.h>
    #include <unistd.h>
    #include <pty.h>
    
    FILE *
    pty_execvp (char *argv[], pid_t *child)
    {
      int pty;
      struct termios t;
      cfmakeraw(&t);
    
      if (!(*child = forkpty(&pty, 0, &t, 0))) {
        execvp(argv[0], argv);
        fprintf(stderr, "exec %s: %m\n", argv[0]);
        exit(127);
      } else if (*child == -1)
        return 0;
    
      return fdopen(pty, "r+");
    }
    

    类似于popen ,它返回FILE *与伪终端相关联,在伪终端上,具有给定参数的脚本(程序)在新进程中启动。

    带有脚本的文件的名称及其参数的传递方式与execvp函数中的方式相同(只有脚本的第一个参数被用作要启动的文件的名称)。

    child此进程的 pid 位于参数中的地址。

    您需要使用 -lutil 选项进行构建(请参阅man forkpty)。

    这是一个(有点麻烦和人为的)使用示例

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <poll.h>
    
    
    FILE *pty_execvp (char *argv[], pid_t *child);
    
    int
    fd_out (int fd, FILE *out, int tmout)
    {
      struct pollfd fds = {fd, POLLIN};
      char buf[1024];
      int l, s = 0;
    
      while (poll(&fds, 1, tmout) > 0) {
        if ((l = read(fd, buf, 1024)) > 0) {
          s += l;
          fwrite(buf, 1, l, out);
        } else
          return -1;
      }
    
      return s;
    }
    
    
    int
    main (int ac, char *av[])
    {
      char *line = 0;
      size_t lsz;
      const char *cmd = "ls -l *.txt";
      FILE *in = popen(cmd, "r");
      if (!in)
        perror("popen"), exit(2);
      const char *pcmd[] = {
        "grep",
        "20",
        0
      };
      pid_t cpid;
      FILE *pty = pty_execvp((char **)pcmd, &cpid);
      if (pty)
        printf("run %s pid %ld\n", pcmd[0], (long)cpid);
      else
        exit(fputs("pty-exec error", stderr));
    
      while (getline(&line, &lsz, in) > 0) {
        fputs(line, pty);
        //    printf("> %s", line);
        if (fd_out(fileno(pty), stdout, 0) < 0) {
          perror("fd_out");
          break;
        }
      }
    
      while (fd_out(fileno(pty), stdout, 1) > 0);
    
      int rc;
      rc = pclose(in);
      printf("%s rc = %d\n",
         WIFEXITED(rc) ? "exit" : "terminated", WEXITSTATUS(rc));
      fclose(pty);
      pid_t fin = wait(&rc);
      if (WIFEXITED(rc)) 
        printf("Exit pid:%ld %d\n", (long)fin, WEXITSTATUS(rc));
      else if (WIFSIGNALED(rc))
        printf("Signal pid:%ld %d\n", (long)fin, WTERMSIG(rc));
      else
        printf("??? pid:%ld %d\n", (long)fin, rc);
    
    
      return puts("End") == EOF;
    }
    

    ls -l *.txt | grep 20当我们事先不知道grep对传递的字符串的响应是什么时,此示例给出的结果与显示使用 popen 和 pty_exec 的结果相同。

    fd_out()请注意程序末尾的调用超时。

    • 2
  2. Best Answer
    AccumPlus
    2020-09-20T16:21:25Z2020-09-20T16:21:25Z

    实际上,有多种实施方案。命名管道(named pipes)就是为了我的任务而产生的。

    下面显示了一个实现示例。省略了一些错误处理并且简化了代码本身。

    C++ 的代码片段

    int pipeDescr, bytesNumber;
    std::string outputPipeName{"inputPipe"}, inputPipeName{"outputPipe"};
    char message[BUFSIZ];
    
    if (mkfifo(inputPipeName.c_str(), 0777) || mkfifo(outputPipeName.c_str(), 0777))
    {
        perror("mkfifo");
        return 1;
    }
    
    memset(message, '\0', BUFSIZ);
    strcpy(message, "Sample message");
    
    if ((pipeDescr = open(outputPipeName.c_str(), O_WRONLY)) <= 0)
    {
        perror("open");
        return 2;
    }
    
    bytesNumber = write(pipeDescr, message, strlen(message) + 1);
    if (bytesNumber <= 0)
    {
        perror("write");
        return 3;
    }
    close(pipeDescr);
    
    memset(message, '\0', BUFSIZ);
    if ((pipeDescr = open(inputPipeName.c_str(), O_RDONLY)) <= 0)
    {
        perror("open");
        return 2;
    }
    
    bytesNumber = read(pipeDescr, message, BUFSIZ);
    if (bytesNumber <= 0)
    {
        perror("read");
        return 4;
    }
    close(pipeDescr);
    
    std::cout << "Got message: " << message << std::endl;
    
    remove(inputPipeName.c_str());
    remove(outputPipeName.c_str());
    

    Python 的代码片段

    input_pipe_name = "inputPipe"
    output_pipe_name = "outputPipe"
    
    while not os.path.exists(input_pipe_name) and not os.path.exists(output_pipe_name):
        pass
    
    try:
        pipe_descr = os.open(input_pipe_name, os.O_RDONLY)
        mes = os.read(pipe_descr, 1024)
        os.close(pipe_descr)
        print('Got: ' + str(mes))
    
        mes = 'Some answer'
        pipe_descr = os.open(output_pipe_name, os.O_WRONLY)
        os.write(pipe_descr, bytes(mes, 'UTF-8'))
        os.close(pipe_descr)
    except OSEerror as exc:
        print('Exception: ' + str(exc))
    

    用 C++ 编写的程序的进程首先开始,因为它创建频道文件。

    • 1
  3. jfs
    2020-10-04T01:35:45Z2020-10-04T01:35:45Z

    从你关于信号的问题来看,我会简化进程通信,例如,你可以在 Python 中使用标准输入/输出进行写入和读取:

    #!/usr/bin/env python3
    import sys
    
    for line in sys.stdin:
        print(work_func(line), flush=True)
    

    要在 之后将子进程的 I/O 重定向到 C fork(),您可以dup2()使用. 或者更简单,使用socketpair. 如果需要,您可以使用共享内存 ( mmap, posix_ipc)。

    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5