在C中读/写结构到fifo

发布于 2024-11-08 19:50:20 字数 2788 浏览 0 评论 0 原文

我正在尝试使用命名管道在进程之间传递结构。我在尝试打开管道非阻塞模式时陷入困境。这是我写入 fifo 的代码:

void writeUpdate() {
    // Create fifo for writing updates:
    strcpy(fifo_write, routing_table->routerName);
    // Check if fifo exists:
    if(access(fifo_write, F_OK) == -1 )
        fd_write = mkfifo(fifo_write, 0777);
    else if(access(fifo_write, F_OK) == 0) {
        printf("writeUpdate: FIFO %s already exists\n", fifo_write);
        //fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
    }
    fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
    if(fd_write < 0)
        perror("Create fifo error");
    else {
        int num_bytes = write(fd_write, routing_table, sizeof(routing_table));
        if(num_bytes == 0)
            printf("Nothing was written to FIFO %s\n", fifo_write);
        printf("Wrote %d bytes. Sizeof struct: %d\n", num_bytes,sizeof(routing_table)+1);
        }
    close(fd_write);
   }

routing_table 是指向我的结构的指针,它已分配,因此 fifo 或类似名称不存在问题。 如果我在没有 O_NONBLOCK 选项的情况下打开 fifo,它会第一次写入,但随后它会阻塞,因为我在读取结构时也遇到了麻烦。第一次之后,创建了初始 fifo,但出现了其他 fifo,名为“.”、“...”。 设置 O_NONBLOCK 选项后,它会创建 fifo,但总是抛出错误:“没有这样的设备或地址”。知道为什么会发生这种情况吗?谢谢。

编辑:好的,我现在很清楚如何打开 fifo,但我还有另一个问题,实际上将结构读/写到 fifo 是我的问题。我读取结构的代码:

void readUpdate() {
struct rttable *updateData;
allocate();

strcpy(fifo_read, routing_table->table[0].router);

// Check if fifo exists:
if(access(fifo_read, F_OK) == -1 )
    fd_read = mkfifo(fifo_read, 777);
else if(access(fifo_read, F_OK) == 0) {
    printf("ReadUpdate: FIFO %s already exists\n Reading from %s\n", fifo_read, fifo_read);        
}
fd_read = open(fifo_read, O_RDONLY|O_NONBLOCK);
int num_bytes = read(fd_read, updateData, sizeof(updateData));
close(fd_read);
if(num_bytes > 0) {
    if(updateData == NULL)
        printf("Read data is null: yes");
    else
        printf("Read from fifo: %s %d\n", updateData->routerName, num_bytes);

    int result = unlink(fifo_read);
    if(result < 0)
        perror("Unlink fifo error\n");
    else {
        printf("Unlinking successful for fifo %s\n", fifo_read);
        printf("Updating table..\n");
        //update(updateData);
        print_table_update(updateData);
    }
} else
    printf("Nothing was read from FIFO %s\n", fifo_read);
}

它打开 fifo 并尝试读取,但 fifo 中似乎没有任何内容,尽管在 writeUpdate 中第一次说它写入了 4 个字节(这似乎也是错误的)。读取时,第一次打印“a”,然后 num_bytes 始终 <= 0。 我环顾四周,只找到了这个例子,只有简单的写入/读取,在编写结构时还需要什么吗?

我的结构如下所示:

typedef struct distance_table {
char dest[20];       //destination network
char router[20];     // via router..
int distance;
} distance_table;

typedef struct rttable {
char routerName[10];
char networkName[20];
struct distance_table table[50];
int nrRouters;
} rttable;

struct rttable *routing_table;

I'm trying to pass structs between processes using named pipes. I got stuck at trying to open the pipe non-blocking mode. Here's my code for writing to the fifo:

void writeUpdate() {
    // Create fifo for writing updates:
    strcpy(fifo_write, routing_table->routerName);
    // Check if fifo exists:
    if(access(fifo_write, F_OK) == -1 )
        fd_write = mkfifo(fifo_write, 0777);
    else if(access(fifo_write, F_OK) == 0) {
        printf("writeUpdate: FIFO %s already exists\n", fifo_write);
        //fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
    }
    fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
    if(fd_write < 0)
        perror("Create fifo error");
    else {
        int num_bytes = write(fd_write, routing_table, sizeof(routing_table));
        if(num_bytes == 0)
            printf("Nothing was written to FIFO %s\n", fifo_write);
        printf("Wrote %d bytes. Sizeof struct: %d\n", num_bytes,sizeof(routing_table)+1);
        }
    close(fd_write);
   }

routing_table is a pointer to my struct, it's allocated, so there's no prob with the name of the fifo or smth like that.
If I open the fifo without the O_NONBLOCK option, it writes smth for the first time, but then it blocks because I'm having troubles reading the struct too. And after the first time, the initial fifo is created, but other fifo's appear, named '.', '..'.
With O_NONBLOCK option set, it creates the fifo but always throws an error: 'No such device or address'. Any idea why this happens? Thanks.

EDIT: Ok, so I'm clear now about opening the fifo, but I have another problem, in fact reading/writing the struct to the fifo was my issue to start with. My code to read the struct:

void readUpdate() {
struct rttable *updateData;
allocate();

strcpy(fifo_read, routing_table->table[0].router);

// Check if fifo exists:
if(access(fifo_read, F_OK) == -1 )
    fd_read = mkfifo(fifo_read, 777);
else if(access(fifo_read, F_OK) == 0) {
    printf("ReadUpdate: FIFO %s already exists\n Reading from %s\n", fifo_read, fifo_read);        
}
fd_read = open(fifo_read, O_RDONLY|O_NONBLOCK);
int num_bytes = read(fd_read, updateData, sizeof(updateData));
close(fd_read);
if(num_bytes > 0) {
    if(updateData == NULL)
        printf("Read data is null: yes");
    else
        printf("Read from fifo: %s %d\n", updateData->routerName, num_bytes);

    int result = unlink(fifo_read);
    if(result < 0)
        perror("Unlink fifo error\n");
    else {
        printf("Unlinking successful for fifo %s\n", fifo_read);
        printf("Updating table..\n");
        //update(updateData);
        print_table_update(updateData);
    }
} else
    printf("Nothing was read from FIFO %s\n", fifo_read);
}

It opens the fifo and tries to read, but it seems like nothing is in the fifo, although in writeUpdate the first time it says it wrote 4 bytes (this seems wrong too). At reading, first time around it prints 'a' and then num_bytes is always <=0.
I've looked around and only found this example, with simple write/read, is there smth more needed when writing a struct?

My struct looks like this:

typedef struct distance_table {
char dest[20];       //destination network
char router[20];     // via router..
int distance;
} distance_table;

typedef struct rttable {
char routerName[10];
char networkName[20];
struct distance_table table[50];
int nrRouters;
} rttable;

struct rttable *routing_table;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

偏爱自由 2024-11-15 19:50:20

ENXIO 错误消息是“没有这样的设备或地址”。如果您查看 open< /code> 手册页,您会看到报告此错误,特别是在以下情况下:

O_NONBLOCK | O_WRONLY 被设置,指定的文件是 FIFO 并且没有进程
打开文件以供读取。 (...)

这正是你的情况。因此,您看到的行为是正常的:您无法写入(不阻塞)到没有读取器的管道。如果没有任何内容连接到管道进行读取,内核将不会缓冲您的消息。

因此,请确保在“生产者”之前启动“消费者”,或者删除生产者上的非阻塞选项。

顺便说一句:在大多数情况下,使用 access 是向 检查时间到使用时间问题。不要使用它。尝试一下mkfifo - 如果它有效,那么你就很好了。如果失败并显示 EEXISTS,那么您也可以。如果否则失败,请清理并退出。

对于问题的第二部分,这实际上完全取决于您尝试发送的数据的结构。在 C 中序列化随机结构根本不容易,特别是如果它包含变量数据(例如 char *)。

如果您的结构仅包含原始类型(并且没有指针),并且两侧都在同一台机器上(并使用相同的编译器编译),则一侧是原始 write ,而 read< /code> 整个结构的另一个应该可以工作。

例如,您可以查看C - 序列化技术以获取更复杂的数据类型。

关于您的具体示例:您会混淆指向结构的指针和普通结构。

在写入方面,您有:

int num_bytes = write(fd_write, routing_table, sizeof(routing_table));

这是不正确的,因为 routing_table 是一个指针。您需要:

int num_bytes = write(fd_write, routing_table, sizeof(*routing_table));
// or sizeof(struct rttable)

读取端同样的东西。据我所知,在接收大小上,您也没有分配 updateData 。您也需要这样做(使用malloc,并记住释放它)。

struct rttable *updateData = malloc(sizeof(struct rrtable));

"No such device or address" is the ENXIO error message. If you look at the open man page, you'll see that this error is reported in particular if:

O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process
has the file open for reading. (...)

which is exactly your situation. So the behavior you are seeing is normal: you can't write (without blocking) to a pipe that has no readers. The kernel won't buffer your messages if nothing is connected to the pipe for reading.

So make sure you start the "consumer(s)" before your "producer", or remove the non-blocking option on the producer.

BTW: using access is, in most circumstances, opening yourself to time of check to time of use issues. Don't use it. Try the mkfifo - if it works, you're good. If it fails with EEXISTS, you're good too. If it fails otherwise, clean up and bail out.

For the second part of your question, it really depends completely on how exactly the data you are trying to send is structured. Serializing a random struct in C is not easy at all, especially if it contains variable data (like char *s for example).

If you struct contains only primitive types (and no pointers), and both sides are on the same machine (and compiled with the same compiler), then a raw write on one side and read on the other of the whole struct should work.

You can look at C - Serialization techniques for more complex data types for example.

Concerning your specific example: you're getting mixed up between pointers to your structs and plain structs.

On the write side you have:

int num_bytes = write(fd_write, routing_table, sizeof(routing_table));

This is incorrect since routing_table is a pointer. You need:

int num_bytes = write(fd_write, routing_table, sizeof(*routing_table));
// or sizeof(struct rttable)

Same thing on the read side. On the receiving size you're also not allocating updateData as far as I can tell. You need to do that too (with malloc, and remember to free it).

struct rttable *updateData = malloc(sizeof(struct rrtable));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文