2011-05-21 65 views
2

我试图在使用命名管道的进程之间传递结构。我被困在试图打开管道非阻塞模式。这里是我的代码写入FIFO:在C中读/写struct到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,它会第一次写入smth,但是会阻塞,因为我也有麻烦读取结构。第一次之后,最初的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; 

回答

2

“没有这样的设备或地址”是ENXIO错误消息。如果你看一下open手册页,你会看到这个错误发生在特定的报告,如果:

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

这正是你的状况。所以你看到的行为是正常的:你不能写入(没有阻塞)到没有阅读器的管道。如果没有任何东西连接到管道进行读取,内核将不会缓冲您的消息。

因此,请确保您在“制作人”之前启动“消费者”,或删除制作人的非阻止选项。

顺便说一句:使用access是在大多数情况下,打开自己time of check to time of use问题。不要使用它。尝试mkfifo - 如果它有效,你很好。如果它失败EEXISTS,你也很好。如果失败,则清理并纾困。

对于问题的第二部分,它完全取决于您尝试发送的数据的结构。在C中序列化一个随机结构并不容易,尤其是如果它包含可变数据(例如char * s)。

如果结构只包含基本类型(没有指针),并且双方都在同一台机器上(和相同的编译器编译),则原始write一边和read上之外的整个结构的应该管用。

例如,您可以查看C - Serialization techniques获取更复杂的数据类型。

关于你的具体例子:你在指向你的结构和普通结构的指针之间混在一起。

写入侧您有:

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)); 
+0

您的权利,但我将不得不写结构来说,3-5其他进程,并为每一个我会打开一个不同的先进先出。如果其中一个'消费者'进程没有读取数据,我的整个生产者进程就会挂起。所以我想定期写入fifo,并以某种方式检查消费者是否读取数据。整个目的是模拟路由协议(距离向量),不知道我是否有最好的想法。 – joanna 2011-05-21 09:29:44

+0

当你在'open'上发现错误时,你知道没有消费者,所以写作没有意义 - 没有人会在另一端阅读。所以你的方法适用于'O_NONBLOCK' - 你知道消费者没有阅读。 – Mat 2011-05-21 09:43:56

+1

使用access()也是错误的另一个原因,因为它不一定检查您的有效权限。 – augustss 2011-05-21 09:46:17