【问题标题】:Named pipe, read fail with bad file descriptor命名管道,读取失败,文件描述符错误
【发布时间】:2017-07-05 13:13:01
【问题描述】:

我从 Linux 下的管道开始,但我的代码有问题。 我想测试通过fifo发送一个整数,所以我编写了一个小程序来测试它。

首先我打开只读描述符,然后打开文档中精确的只写描述符。 我将数字发送到管道并关闭写描述符。

但是,当我尝试从管道读取数据时,它说我有一个错误的文件描述符,我不明白为什么它不起作用,因为描述符是好的描述符,并且打开时有好的选项( O_RDONLY | O_NONBLOCK)。

这是我的代码:

void main(void)
{
    int modePipeWrite, modePipeRead;

    if(mkfifo("test.fifo", 0777) == -1)
    {
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }
    if(modePipeRead = open("test.fifo", O_RDONLY | O_NONBLOCK) == -1)
    {
        perror("openRead");
        exit(EXIT_FAILURE);
    }
    if(modePipeWrite = open("test.fifo", O_WRONLY | O_NONBLOCK) == -1)
    {
        perror("openWrite");
        exit(EXIT_FAILURE);
    }


    int n = 0;

    if(write(modePipeWrite, &n, sizeof(n)) == -1)
    {
        perror("write");
    }
    printf("Send value: %d\n", n);

    close(modePipeWrite);


    int mode;

    while(1)
    {
        if(read(modePipeRead, &mode, sizeof(mode)) == -1)
        {
            perror("read");
        }
        printf("Received value: %d\n", getpid(), mode);
        sleep(1);
    }
}

还有输出:

./a.out
Send value: 0

read: Bad file descriptor
Received value: -1877110288

read: Bad file descriptor
Received value: -1877110288

read: Bad file descriptor
Received value: -1877110288

我不明白这里有什么问题。如果有人有一些建议,我会很高兴听到它。

【问题讨论】:

  • 我无法立即解释问题的确切性质,但管道是一种进程间通信的机制。它们既不适合也不适合单个进程与自身通信。
  • 我猜你不应该关闭管道,直到你读完它。
  • 也许,@mustaccio,但他将读写端作为单独的文件打开,所以这一点都不清楚。我怀疑这是(1)以非阻塞模式打开两端,(2)在同一进程中,(3)在读取之前关闭写入端的部分或全部的组合。
  • 也许删除O_NONBLOCK
  • 还请注意,从用户程序的角度来看,Linux 中有两种不同的管道:命名 管道,也称为 FIFO,以及通过 pipe() 创建的匿名管道功能。后者是迄今为止更常用的。

标签: c linux pipe


【解决方案1】:

您的代码有几个问题,如果您在编译时启用所有警告就会发现这些问题。如果您使用 gcc,则以下选项很好/强制: -Wall -Wextra -Werror -pedantic

一个问题是您没有将 open() 的返回值分配给文件描述符。您需要在分配周围添加大括号,或将其移出 if 语句。

这是一个工作示例,使用线程读取:

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

#include <pthread.h>

static void *reader(void *arg)
{   
    int fd, val;

    if ((fd = open("test.fifo", O_RDONLY)) == -1) {
        perror("openRead");
        exit(EXIT_FAILURE);
    }

    if (read(fd, &val, sizeof val) == -1)
        perror("read");
    else
        printf("Received value: %d\n", val);

    close(fd);
    return NULL;
}

int main(void)
{   
    int modePipeWrite, modePipeRead;
    pthread_t readerid;


    if (mkfifo("test.fifo", 0777) == -1) {
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }
    pthread_create(&readerid, NULL, reader, NULL);
    sleep(1);

    if ((modePipeWrite = open("test.fifo", O_WRONLY)) == -1) {
        perror("openWrite");
        exit(EXIT_FAILURE);
    }

    int n = 1234;

    if (write(modePipeWrite, &n, sizeof n) == -1)
        perror("write");
    else
        printf("Sent value: %d\n", n);

    sleep(1);
    close(modePipeWrite);

    return 0;
}

【讨论】:

  • 无法意识到它是如此简单......非常感谢您的帮助,它正在按我的预期工作。只是一个问题,如何将 shell 中的整数写入管道?因为当我在执行“cat 4 > test.fifo”时,读取值更改为 2612,但是当我从另一个程序执行此操作时,就可以了。
  • 4 只是一个 ASCII 值。您要么需要将其转换为四字节整数,要么——更好地——读取程序中的文本并将其转换为整数。 (也许 fdopen() 和 fscanf() 会有用?)
  • 我虽然可以告诉 shell 将 4 解释为整数值。无论这与主题绝对无关,我稍后会挖掘。再次感谢;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-18
  • 1970-01-01
  • 2010-11-06
  • 2012-06-01
相关资源
最近更新 更多