【问题标题】:Redirecting stdin with FIFO (names pipe)使用 FIFO 重定向标准输入(名称管道)
【发布时间】:2015-12-02 06:17:24
【问题描述】:

我正在创建一个带有服务器-客户端基础的 C 程序。

我一直在尝试将标准输入重定向到我创建的命名管道,并且我已经设法将客户端写入管道。在服务器端,我打开了相同的管道,关闭了标准输入并使用 dup(也尝试使用 dup2)将标准输入重定向到管道。

我必须使用函数 getline 读取输入。问题是它正确读取了第一个输入,但之后只收到空值。我将在问题中添加一个示例。

服务器:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


main () {
    char* str;
    size_t size=0;
    int pshell_in;

    unlink("/tmp/par-shell-in"); 
    if(mkfifo("/tmp/par-shell-in", 0777) < 0){
        fprintf(stderr, "Error: Could not create pipe\n");
        exit(-1);
    }

    if((pshell_in = open("/tmp/par-shell-in", O_CREAT | O_RDONLY, S_IRUSR)) < 0){
        fprintf(stderr, "Error: Failed to open file\n");
        exit(-1);   
    }

    dup2(pshell_in, 0);
    close(pshell_in);



    while(1) {
        if (getline(&str, &size, stdin)<0) {
            printf("Oh dear, something went wrong with getline()! %s\n", strerror(errno));
            return -1;
        }

        printf("%s", str);
    }
}

* 我知道它的 null 因为我已经用 read(而不是重定向)打印它并且它打印 (null)。

客户:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h> 
#include <string.h>
#include <fcntl.h>

#define VECTORSIZE 7

int main() {

    char* buf;
    int pshell_in;
    size_t size=0;

    if((pshell_in = open("/tmp/par-shell-in", O_WRONLY, S_IWUSR)) < 0){
        fprintf(stderr, "Error: Failed to open file\n");
        exit(-1);   
    }

    printf("%d\n", pshell_in);

    while(1) {
        if (getline(&buf, &size, stdin) < 0) {
            return -1;
        }

        write(pshell_in, buf, 256);
    }
}
  • 我怀疑它是正确的,因为如果我在客户端使用 read(将 O_WRONLY 替换为 O_RDWR),它会在我键入时打印字符串。

谁能帮我解决这个问题?

【问题讨论】:

    标签: c pipe stdin fifo dup


    【解决方案1】:

    FIFO 很有趣。如果一个进程试图打开一个读取,它将阻塞,直到有一个进程打开它进行写入。相反,如果一个进程试图打开一个进行写入,它将阻塞,直到有一个进程打开它进行读取。但是,多个进程可以打开它进行读取或写入。当没有更多进程可以读取时,写入将失败;当没有更多进程可以写入时,读取将失败。而当操作失败时,您必须关闭并重新打开 FIFO 才能继续重新处理数据。

    我强烈怀疑您会因为这些行为而遇到问题。

    此外,您的客户编写代码是可疑的;您没有注意读取了多少数据。你有:

    while(1) {
        if (getline(&buf, &size, stdin) < 0) {
            return -1;
        }
        write(pshell_in, buf, 256);
    }
    

    如果很可能您在该行中读取的输入字符少于 256 个字符,那么您很可能会超出getline() 分配的数组边界。一些甚至大部分数据也很可能是空字节。但是,您在服务器中看到的 (null) 通常表明您正在尝试打印字符串,但传递了 printf() 一个空指针。无论发生了什么,大部分都是未定义的行为,这是一件坏事™,应该不惜一切代价避免。

    你应该有更多类似的东西:

    ssize_t nbytes;
    
    while ((nbytes = getline(&buf, &size, stdin)) > 0)
    {
        if (write(pshell_in, buf, nbytes) != nbytes)
        {
            fprintf(stderr, "Short write to FIFO\n");
            break;
        }
    }
    free(buf);
    

    请注意,它只写入与读取一样多的数据,并且不假设有 256 个字节可供写入。

    【讨论】:

      猜你喜欢
      • 2011-06-01
      • 1970-01-01
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-16
      相关资源
      最近更新 更多