ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

与子进程stdout / stdin通信

2019-11-22 07:00:56  阅读:405  来源: 互联网

标签:stdout c-3 linux pipe ipc


我正在尝试与进程通信(该进程本身会写入stdin和stdout以便在终端中与用户进行交互),并读取它的stdin并在C中写入它的stdout.

因此,我尝试以编程方式替换shell用户.一个比较简单的例子:想象一下,出于某种原因,我想在C语言中使用VIM.然后,我还需要编写命令(stdout)并从编辑器(stdin)中读取内容.

最初,我认为这可能是一件微不足道的任务,但似乎没有标准方法. int system(const char * command);只需执行一个命令并将命令stdin / stdout设置为调用进程之一即可.

因为这无济于事,所以我看了FILE * popen(const char * command,const char * type);但手册页指出:

Since a pipe is by definition unidirectional, the type argument may specify only reading or writing, not both; the resulting stream is correspondingly read-only or write-only.

及其含义:

The return value from popen() is a normal standard I/O stream in all respects save that it must be closed with pclose() rather than fclose(3). Writing to such a stream writes to the standard input
of the command;
the command’s standard output is the same as that of the process that called popen(), unless this is altered by the command itself. Conversely, reading from a “popened” stream reads
the command’s standard output
, and the command’s standard input is the same as that of the process that called popen().

因此,使用popen()并不是完全不可能的,但是在我看来,这很不雅致,因为我必须解析调用过程的stdout(调用popen()的代码)才能解析从弹出的命令(使用popen类型时,使用“ w”).

相反,当使用类型’r’调用popen时,我将需要写入调用进程的stdin,以便将数据写入popened命令.在这种情况下,我什至还不清楚这两个进程在stdin中是否都接收到相同的数据…

我只需要控制程序的stdin和stdout.我的意思是不能有这样的功能:

stdin_of_process, stdout_of_process = real_popen("/path/to/bin", "rw")
// write some data to the process stdin
write("hello", stdin_of_process)
// read the response of the process
read(stdout_of_process)

所以我的第一个问题是:实现上层功能的最佳方法是什么?

目前,我正在尝试以下方法与另一个进程进行通信:

>用int pipe(int fildes [2]);设置两个管道.一个管道读取进程的stdout,另一个管道写入进程的stdin.
>叉子.
>使用int execvp(const char * file,char * const argv []);在派生的子进程中执行我想与之通信的进程.
>在原始过程中使用两个管道与孩子沟通.

这很容易说,机器人并不是那么简单地实现(至少对我而言).在一种情况下,我很奇怪地做到了这一点,但是当我试图通过一个简单的例子来了解自己在做什么时,我失败了.这是我当前的问题:

我有两个程序.第一个只是每100毫秒向其标准输出写入一个递增的数字:

#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

void sleepMs(uint32_t ms) {
    struct timespec ts;
    ts.tv_sec = 0 + (ms / 1000);
    ts.tv_nsec = 1000 * 1000 * (ms % 1000);
    nanosleep(&ts, NULL);
}

int main(int argc, char *argv[]) {
    long int cnt = 0;
    char buf[0x10] = {0};

    while (1) {
        sleepMs(100);
        sprintf(buf, "%ld\n", ++cnt);
        if (write(STDOUT_FILENO, buf, strlen(buf)) == -1)
            perror("write");
    }
}

现在,第二个程序应该读取第一个程序的标准输出(请记住,我最终想用一个进程进行读写,因此对于上层用例使用popen()的技术正确解决方案可能是正确的在这种情况下,因为我简化了实验以仅捕获底层程序的标准输出).我期望从底层程序读取上层程序写入stdout的所有数据.但是它什么也没读.原因可能在哪里? (第二个问题).

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <time.h>

void sleepMs(uint32_t ms) {
    struct timespec ts;
    ts.tv_sec = 0 + (ms / 1000);
    ts.tv_nsec = 1000 * 1000 * (ms % 1000);
    nanosleep(&ts, NULL);
}

int main() {
    int pipe_fds[2];
    int n;
    char buf[0x100] = {0};
    pid_t pid;

    pipe(pipe_fds);

    char *cmd[] = {"/path/to/program/above", NULL};

    if ((pid = fork()) == 0) { /* child */
        dup2(pipe_fds[1], 1); // set stdout of the process to the write end of the pipe
        execvp(cmd[0], cmd); // execute the program.
        fflush(stdout);
        perror(cmd[0]); // only reached in case of error
        exit(0);
    } else if (pid == -1) { /* failed */
        perror("fork");
        exit(1);
    } else { /* parent */

        while (1) {
            sleepMs(500); // Wait a bit to let the child program run a little
            printf("Trying to read\n");
            if ((n = read(pipe_fds[0], buf, 0x100)) >= 0) { // Try to read stdout of the child process from the read end of the pipe
                buf[n] = 0; /* terminate the string */
                fprintf(stderr, "Got: %s", buf); // this should print "1 2 3 4 5 6 7 8 9 10 ..."
            } else {
                fprintf(stderr, "read failed\n");
                perror("read");
            }
        }
    }
}

解决方法:

Here是(带有C 11口味的)完整示例.

但是,出于许多实际目的,Expect library可能是一个不错的选择(请查看其源代码发布的example子目录中的代码).

标签:stdout,c-3,linux,pipe,ipc
来源: https://codeday.me/bug/20191122/2057886.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有