Чтение / запись struct to fifo в C


Я пытаюсь передавать структуры между процессами с помощью именованных каналов. Я застрял при попытке открыть трубу в неблокирующем режиме. Вот мой код для записи в 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 existsn", 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 %sn", fifo_write);
        printf("Wrote %d bytes. Sizeof struct: %dn", num_bytes,sizeof(routing_table)+1);
        }
    close(fd_write);
   }

Routing_table-это указатель на мою структуру, он выделен, поэтому нет проблем с именем fifo или smth, как это. Если я открываю fifo без опции O_NONBLOCK, он записывает smth в первый раз, но затем блокирует, потому что у меня тоже возникают проблемы с чтением структуры. А после первого раза ... первоначальный ФИФО создается, но появляются другие ФИФО, названные '.', '..". С установленным параметром O_NONBLOCK он создает fifo, но всегда выдает ошибку: "нет такого устройства или адреса". Есть идеи, почему это происходит? Спасибо.

EDIT: хорошо, теперь мне ясно, как открыть 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 existsn Reading from %sn", 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 %dn", updateData->routerName, num_bytes);

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

Он открывает ФИФО и пытается читать, но кажется, что в нем ничего нет. fifo, хотя в writeUpdate в первый раз он говорит, что написал 4 байта (это тоже кажется неправильным). При чтении, первый раз он печатает 'A' и затем число_байт всегда

Моя структура выглядит так:

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;
1 2

1 ответ:

"Нет такого устройства или адреса" - это сообщение об ошибке ENXIO. Если вы посмотрите на open man page, вы увидите, что эта ошибка сообщается, в частности, если:

O_nonblock / O_WRONLY установлен, именованный файл-это FIFO, а не процесс файл открыт для чтения. (...)

Что в точности соответствует вашей ситуации. Таким образом, поведение, которое вы видите, является нормальным: вы не можете писать (без блокировки) в канал, который не имеет считывателей. Ядро не будет буферизоваться ваши сообщения, если ничего не подключено к трубе для чтения.

Поэтому убедитесь, что вы запускаете " потребитель (ы) "перед вашим" производителем", или удалите неблокирующую опцию на производителе.

Кстати: использование access в большинстве случаев означает открытие себя для времени проверки до времени использования проблем. Не используйте его. Попробуйте mkfifo - если это работает, Вы хороши. Если это не удается с EEXISTS, Вы тоже хороши. Если это не сработает в противном случае, убирайтесь и спасайтесь.

Для второй части ваш вопрос, это действительно полностью зависит от того, как именно структурированы данные, которые вы пытаетесь отправить. Сериализация случайной структуры в языке C совсем не проста, особенно если она содержит переменные данные (например, char *s).

Если ваша структура содержит только примитивные типы (и никаких указателей), и обе стороны находятся на одной машине (и компилируются одним компилятором), то raw write с одной стороны и read с другой из всей структуры должны работать.

Вы можете посмотреть на методы 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));