Чтение / запись структуры в fifo на C - PullRequest
3 голосов
/ 21 мая 2011

Я пытаюсь передать структуры между процессами, используя именованные каналы.Я застрял при попытке открыть неблокирующий режим трубы.Вот мой код для записи в 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 или что-то вроде этого.Если я открываю fifo без опции O_NONBLOCK, он впервые пишет что-то, но затем блокирует, потому что у меня тоже проблемы с чтением структуры.И после первого раза создается начальный 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.Я осмотрелся и нашел только этот пример с простой записью / чтением. Нужно ли что-то большее при написании структуры?</p>

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

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 Ответ

3 голосов
/ 21 мая 2011

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

O_NONBLOCK | O_WRONLY установлен, названный файл является FIFO и не процесс файл открыт для чтения (...)

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

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

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

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

Если вы структурируете, содержит только примитивные типы (и не имеют указателей), и обе стороны находятся на одной машине (и скомпилированы с одним и тем же компилятором), то необработанный 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));
...