简体   繁体   English

(c / c ++)试图从父进程强制EOF向子进程发送输入

[英](c/c++) trying to force EOF from parent process sending input to child process

i have a very simple c/c++ program that forks a child process to execute another program, and then sends some data to that child program, and waits for the response. 我有一个非常简单的c / c ++程序,它要求子进程执行另一个程序,然后将一些数据发送到该子程序,并等待响应。

the child program reads from stdin and waits for EOF before it continues. 子程序从stdin读取并在继续之前等待EOF。

my problem is, the child program receives the initial input from the pipe writing, but it never sees an EOF (even though I close the pipe), so it waits forever. 我的问题是,子程序从管道写入接收初始输入,但它从未看到EOF(即使我关闭管道),所以它永远等待。

i'm not sure why closing the pipe doesn't imply the EOF for the child's stdin? 我不确定为什么关闭管道并不意味着孩子的stdin的EOF?

here's the code: 这是代码:

http://gist.github.com/621210 http://gist.github.com/621210

The most common reason for this is that you aren't closing the write end of the pipe, so the EOF never gets sent. 最常见的原因是您没有关闭管道的写入端,因此EOF永远不会被发送。 The common example is when you have code that looks like: 常见的例子是当您的代码如下所示:

int fds[2];
pipe(fds);  // open a pipe
if (fork()) {
    // parent process
    write(fds[1], ...  // write data
    close(fds[1]); // close it
} else {
    // child process
    while (read(fds[0], ....) > 0) {
        // read until EOF

The problem here is that the write end of the pipe never gets closed -- the parent process closes it, but the child still has the write descriptor open. 这里的问题是管道的写端不会被关闭 - 父进程关闭它,但子进程仍然打开了写描述符。 So the child never sees an EOF on the read descriptor. 因此,孩子永远不会在读取描述符上看到EOF。

The very first thing you need to do after forking the child is to close(fds[1]); 分娩后你需要做的第一件事就是close(fds[1]); , closing its copy of the write descriptor. ,关闭其写入描述符的副本。 That way when the parent closes the last remaining reference to the write end of the pipe, the child will see EOF on the read end. 这样,当父级关闭对管道写入端的最后一个剩余引用时,子级将在读取端看到EOF。

Edit 编辑

looking at the link you added, this is precisely the problem -- the child still has the write end of the pipe open on its stdout. 看看你添加的链接,这正是问题 - 孩子仍然在其标准输出上打开管道的写端。 Don't dup the write end to stdout in the child, just close it. 不要将写入结束复制到子项中的stdout,只需将其关闭即可。 Send stdout somewhere else (a logfile, or /dev/null) 在其他地方发送stdout(日志文件或/ dev / null)

Edit 编辑

for bi-drectional communication, you'll need two pipes: 对于双向沟通,你需要两个管道:

int tochild[2], fromchild[2];
pipe(tochild); pipe(fromchild);
if (fork()) {
    close(tochild[0]);
    close(fromchild[1]);
    //write to tochild[1] and read from fromchild[0]
} else {
    dup2(tochild[0], 0);
    dup2(fromchild[1], 1);
    close(tochild[0]); close(tochild[1]);
    close(fromchild[0]); close(fromchild[1]);
    exec(...
}

You need to be very careful writing data in the parent, however -- if there's a lot of data to be sent to the child, you can't send all of it before reading the child's output or you might deadlock (both pipes fill up and the parent blocks trying to write more data for the child while the child blocks trying to output). 你需要非常小心地在父母中写入数据 - 但是如果要向孩子发送大量数据,你不能在读取孩子的输出之前发送所有数据,否则你可能会死锁(两个管道都填满了)当子块阻止尝试输出时,父块阻止尝试为子节点写入更多数据。 You need to use poll or select to tell when there's data to read or space to write, and you may want to put the pipes (the parent ends at least) in non-blocking mode. 您需要使用poll或select来判断何时有要读取的数据或要写入的空间,并且您可能希望将管道(父项至少结束)置于非阻塞模式。

Updated with what I think is the problem: You are reading into a character and checking that character for EOF. 更新了我认为的问题:您正在阅读一个角色并检查该角色的EOF。 That is not how the read() system call works. 这不是read()系统调用的工作原理。 It will return a 0 when at EOF. 在EOF时它将返回0。 It does not write an EOF into the buffer. 它不会将EOF写入缓冲区。

Also I see you are reading one character at a time. 我也看到你一次只读一个角色。 This is an awful way to read data. 这是一种读取数据的糟糕方式。 It is several thousand times slower than reading a large buffer, say 4 or 8 kB. 它比读取大缓冲区慢了几千倍,比如4或8 kB。

I believe you also have a common mistake here. 我相信你在这里也有一个共同的错误。 You are not checking the return value of write(). 您没有检查write()的返回值。

The write system call is not guaranteed to write all the data before returning. 写入系统调用不保证在返回之前写入所有数据。 It might write 4000 bytes and return. 它可能会写入4000个字节并返回。 It will return the number of bytes written. 它将返回写入的字节数。 It is then your responsibility to update your buffer pointer and call write again. 然后,您有责任更新缓冲区指针并再次调用write。

Or it might return an error code and it is important for you to check for that. 或者它可能会返回错误代码,因此检查它是很重要的。

This is the proof of concept I wrote for you: 这是我为你写的概念证明:

Fork exec double pipe by dino ciuffetti 由迪诺ciuffetti叉exec双管

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM