输入/输出管道 [英] Piping for input/output

查看:155
本文介绍了输入/输出管道的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是我试图执行指令的原因:



Linux管道作为输入和输出



如何使用管道在两个程序之间发送简单的字符串?



http://tldp.org/LDP/lpg/node11.html



我的问题是沿着问题的线: Linux管道作为输入和输出,但更具体。



基本上,我试图替换:

  / directory / program< input.txt> output.txt 

使用C ++中的管道,以避免使用硬盘驱动器。这是我的代码:

  //使用PLUMBING BEGIN 
int fd_p2c [2],fd_pFc [2],bytes_read ;
//p2c= pipe_to_child,pFc= pipe_from_child(见上面的链接)
pid_t childpid;
char readbuffer [80];
string program_name; //< ----包括程序名+完整路径
string gulp_command; //< ----包括我的逐行stdin程序执行$ ​​b $ b string receive_output =;

pipe(fd_p2c); //创建管道对子
pipe(fd_pFc); //创建管道从子
childpid = fork(); // create fork

if(childpid< 0)
{
cout< Fork failed<< endl;
exit(-1);
}
else if(childpid == 0)
{
dup2(0,fd_p2c [0]); // close stdout&使得p2c的读取结束进入stdout
close(fd_p2c [0]); //关闭p2c的读取结束
close(fd_p2c [1]); //关闭p2c的写入结束
dup2 (1,fd_pFc [1]); // close stdin&使得pFc的读取结束进入stdin
close(fd_pFc [1]); //关闭pFc的写入结束
close(fd_pFc [0]); //关闭读取结束的pFc

//执行所需的程序
execl(program_name.c_str(),program_name.c_str(),(char *)0);
exit(0);
}
else
{
close(fd_p2c [0]); //关闭读取结束p2c
close(fd_pFc [1]); end of pFc

//循环 - 在p2c写入结束时将所有数据发送到子结点
write(fd_p2c [1],gulp_command.c_str(),(strlen(gulp_command.c_str ())));
close(fd_p2c [1]); //关闭p2c的写入结束

//循环 - 在读取结束时接收所有数据到pFc
while(1)
{
bytes_read = read(fd_pFc [0],readbuffer,sizeof(readbuffer));

if(bytes_read< = 0)//如果没有从缓冲区读取...
break; // ... break loop

receive_output + = readbuffer; //将数据附加到字符串
}
close(fd_pFc [0]); //关闭读取结束的pFc
}
pre>

我绝对确定上面的字符串被正确初始化。但是,有两件事情对我来说没有意义:



(1)我执行的程序报告输入文件为空。因为我不是用<调用程序它不应该是期望一个输入文件。相反,它应该期待键盘输入。此外,它应该读取gulp_command中包含的文本。



(2)程序的报告(通过标准输出提供)出现在终端中。这是奇怪的,因为这个管道的目的是将stdout传输到我的字符串receive_output。但是,由于它出现在屏幕上,这表明信息没有正确通过管道传递给变量。如果我在if语句的末尾实现以下内容,

  cout< receive_output<< endl; 

我没有什么,就像字符串是空的。



我的程序目前正在与另一个程序进行通信文本文件。我的程序写入一个文本文件(例如input.txt),它由外部程序读取。然后该程序产生output.txt,它由我的程序读取。所以它是这样的:

 我的代码 - > input.txt  - >程序 - > output.txt  - >我的代码

因此,我的代码目前使用

  system(program< input.txt> output.txt); 

我想用管道替换这个过程。我想将我的输入作为标准输入传递给程序,并让我的代码将该程序的标准输出读取到一个字符串中。

解决方案

您的主要问题是您拥有 dup2()的参数。您需要使用:

  dup2(fd_p2c [0],0); //将读取结束的管道复制到标准输入
dup2(fd_pFc [1],1); //将管道的写端重复到标准输出

我误认了你写为OK我对设置代码进行错误检查,并从 dup2()调用获得了意外的值,告诉我有什么麻烦。



您还没有确保从孩子读取的数据的空终止;如果出现错误,请插入您之前忽略的错误检查。



工作代码(使用诊断),使用 cat 作为最简单的其他命令

  #include< unistd.h> 
#include< string>
#include< iostream>
using namespace std;

int main()
{
int fd_p2c [2],fd_c2p [2],bytes_read;
pid_t childpid;
char readbuffer [80];
string program_name =/ bin / cat;
string gulp_command =这是命令数据发送到子猫(小猫?);
string receive_output =;

if(pipe(fd_p2c)!= 0 || pipe(fd_c2p)!= 0)
{
cerr< 未能管道\\\
;
exit(1);
}
childpid = fork();

if(childpid< 0)
{
cout< Fork failed<< endl;
exit(-1);
}
else if(childpid == 0)
{
if(dup2(fd_p2c [0],0)!= 0 ||
close(fd_p2c [ 0])!= 0 ||
close(fd_p2c [1])!= 0)
{
cerr< 孩子:未能设置标准输入\ n;
exit(1);
}
if(dup2(fd_c2p [1],1)!= 1 ||
close(fd_c2p [1])!= 0 ||
close(fd_c2p [0 ])!= 0)
{
cerr<< 孩子:未能设置标准输出\\\
;
exit(1);
}

execl(program_name.c_str(),program_name.c_str(),(char *)0);
cerr<< 无法执行<< program_name<< endl;
exit(1);
}
else
{
close(fd_p2c [0]);
close(fd_c2p [1]);

cout<< 写给孩子:<< << gulp_command<< >> << endl;
int nbytes = gulp_command.length();
if(write(fd_p2c [1],gulp_command.c_str(),nbytes)!= nbytes)
{
cerr< Parent:short write to child\\\
;
exit(1);
}
close(fd_p2c [1]);

while(1)
{
bytes_read = read(fd_c2p [0],readbuffer,sizeof(readbuffer)-1);

if(bytes_read< = 0)
break;

readbuffer [byte_read] ='\0';
receive_output + = readbuffer;
}
close(fd_c2p [0]);
cout<< From child:<< << receive_output<< >> << endl;
}
return 0;
}

输出示例:

 写入子:<<这是发送到子猫(kitten?)的命令数据>> 
从child:<<这是发送到子cat(kitten?)的命令数据>>






请注意,你不会被你的代码死锁。如果你有一个严格同步的协议(所以父母写一个消息,并在锁步读取响应),你应该没事,但如果父母试图写一个太大的消息,以适应孩子的管道当孩子试图写一个太大的消息,以适合回到父母的管道,那么每个将被阻塞写等待另一个读取。


This question follows from my attempt to implement the instructions in:

Linux Pipes as Input and Output

How to send a simple string between two programs using pipes?

http://tldp.org/LDP/lpg/node11.html

My question is along the lines of the question in: Linux Pipes as Input and Output, but more specific.

Essentially, I am trying to replace:

/directory/program < input.txt > output.txt

using pipes in C++ in order to avoid using the hard drive. Here's my code:

//LET THE PLUMBING BEGIN 
int fd_p2c[2], fd_pFc[2], bytes_read;
    // "p2c" = pipe_to_child, "pFc" = pipe_from_child (see above link)
pid_t childpid;
char readbuffer[80];
string program_name;// <---- includes program name + full path
string gulp_command;// <---- includes my line-by-line stdin for program execution
string receive_output = "";

pipe(fd_p2c);//create pipe-to-child
pipe(fd_pFc);//create pipe-from-child
childpid = fork();//create fork

if (childpid < 0)
{
    cout << "Fork failed" << endl;
    exit(-1);
}
else if (childpid == 0)
{
    dup2(0,fd_p2c[0]);//close stdout & make read end of p2c into stdout
    close(fd_p2c[0]);//close read end of p2c
    close(fd_p2c[1]);//close write end of p2c
    dup2(1,fd_pFc[1]);//close stdin & make read end of pFc into stdin
    close(fd_pFc[1]);//close write end of pFc
    close(fd_pFc[0]);//close read end of pFc

    //Execute the required program
    execl(program_name.c_str(),program_name.c_str(),(char *) 0);
    exit(0);
}
else
{
    close(fd_p2c[0]);//close read end of p2c
    close(fd_pFc[1]);//close write end of pFc

    //"Loop" - send all data to child on write end of p2c
    write(fd_p2c[1], gulp_command.c_str(), (strlen(gulp_command.c_str())));
    close(fd_p2c[1]);//close write end of p2c

    //Loop - receive all data to child on read end of pFc
    while (1)
    {        
        bytes_read = read(fd_pFc[0], readbuffer, sizeof(readbuffer));

        if (bytes_read <= 0)//if nothing read from buffer...
            break;//...break loop

        receive_output += readbuffer;//append data to string
    }
    close(fd_pFc[0]);//close read end of pFc
}

I am absolutely sure that the above strings are initialized properly. However, two things happen that don't make sense to me:

(1) The program I am executing reports that the "input file is empty." Since I am not calling the program with "<" it should not be expecting an input file. Instead, it should be expecting keyboard input. Furthermore, it should be reading the text contained in "gulp_command."

(2) The program's report (provided via standard output) appears in the terminal. This is odd because the purpose of this piping is to transfer stdout to my string "receive_output." But since it is appearing on screen, that indicates to me that the information is not being passed correctly through the pipe to the variable. If I implement the following at the end of the if statement,

cout << receive_output << endl;

I get nothing, as though the string is empty. I appreciate any help you can give me!

EDIT: Clarification

My program currently communicates with another program using text files. My program writes a text file (e.g. input.txt), which is read by the external program. That program then produces output.txt, which is read by my program. So it's something like this:

my code -> input.txt -> program -> output.txt -> my code

Therefore, my code currently uses,

system("program < input.txt > output.txt");

I want to replace this process using pipes. I want to pass my input as standard input to the program, and have my code read the standard output from that program into a string.

解决方案

Your primary problem is that you have the arguments to dup2() reversed. You need to use:

dup2(fd_p2c[0], 0);   // Duplicate read end of pipe to standard input
dup2(fd_pFc[1], 1);   // Duplicate write end of pipe to standard output

I got suckered into misreading what you wrote as OK until I put error checking on the set-up code and got unexpected values from the dup2() calls, which told me what the trouble was. When something goes wrong, insert the error checks you skimped on before.

You also did not ensure null termination of the data read from the child; this code does.

Working code (with diagnostics), using cat as the simplest possible 'other command':

#include <unistd.h>
#include <string>
#include <iostream>
using namespace std;

int main()
{
    int fd_p2c[2], fd_c2p[2], bytes_read;
    pid_t childpid;
    char readbuffer[80];
    string program_name = "/bin/cat";
    string gulp_command = "this is the command data sent to the child cat (kitten?)";
    string receive_output = "";

    if (pipe(fd_p2c) != 0 || pipe(fd_c2p) != 0)
    {
        cerr << "Failed to pipe\n";
        exit(1);
    }
    childpid = fork();

    if (childpid < 0)
    {
        cout << "Fork failed" << endl;
        exit(-1);
    }
    else if (childpid == 0)
    {
        if (dup2(fd_p2c[0], 0) != 0 ||
            close(fd_p2c[0]) != 0 ||
            close(fd_p2c[1]) != 0)
        {
            cerr << "Child: failed to set up standard input\n";
            exit(1);
        }
        if (dup2(fd_c2p[1], 1) != 1 ||
            close(fd_c2p[1]) != 0 ||
            close(fd_c2p[0]) != 0)
        {
            cerr << "Child: failed to set up standard output\n";
            exit(1);
        }

        execl(program_name.c_str(), program_name.c_str(), (char *) 0);
        cerr << "Failed to execute " << program_name << endl;
        exit(1);
    }
    else
    {
        close(fd_p2c[0]);
        close(fd_c2p[1]);

        cout << "Writing to child: <<" << gulp_command << ">>" << endl;
        int nbytes = gulp_command.length();
        if (write(fd_p2c[1], gulp_command.c_str(), nbytes) != nbytes)
        {
            cerr << "Parent: short write to child\n";
            exit(1);
        }
        close(fd_p2c[1]);

        while (1)
        {
            bytes_read = read(fd_c2p[0], readbuffer, sizeof(readbuffer)-1);

            if (bytes_read <= 0)
                break;

            readbuffer[bytes_read] = '\0';
            receive_output += readbuffer;
        }
        close(fd_c2p[0]);
        cout << "From child: <<" << receive_output << ">>" << endl;
    }
    return 0;
}

Sample output:

Writing to child: <<this is the command data sent to the child cat (kitten?)>>
From child: <<this is the command data sent to the child cat (kitten?)>>


Note that you will need to be careful to ensure you don't get deadlocked with your code. If you have a strictly synchronous protocol (so the parent writes a message and reads a response in lock-step), you should be fine, but if the parent is trying to write a message that's too big to fit in the pipe to the child while the child is trying to write a message that's too big to fit in the pipe back to the parent, then each will be blocked writing while waiting for the other to read.

这篇关于输入/输出管道的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆