Чтение и запись данных через канал - PullRequest
2 голосов
/ 07 сентября 2011

Я создал два процесса, используя fork (). Дочерний процесс постоянно генерирует и записывает в канал переменное количество данных (массив символов). Родительский процесс читает из канала и печатает полученные данные в стандартный вывод.

Код очень прост:

switch (fork()) {
  case -1: 
    exit (1);
    break;
  case 0:
    close(fd[0]);
    generate_data(fd[1]);
    break;
  default:
    close(fd[1]);
    while(1) {
        n = read(fd[0], readbuffer, sizeof(readbuffer));
        readbuffer[n] = 0;
        if (n > 0)
            printf ("read: %s\n", readbuffer);            
        else
            exit(1);
    }   
   break;
}   

Где generate_data(int) выполняет итерации по списку, записывая каждый элемент (строку) в дескриптор файла, заданный в качестве аргумента (конец записи канала в данном случае):

void generate_data(int fd) 
{
   node_t node* = list;
   while (node != NULL) {
     write(fd, node->data, strlen(node->data)+1);
     node = node->next();
   }

}

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

Согласно man 2 pipe, этого не должно происходить:

Данные, записанные в конец записи канала, буферизуются ядро, пока оно не будет прочитано с конца чтения канала.

Взяв список из 10 элементов, некоторые примеры вывода:

Пример 1:

read: element_4
read: element_8
read: element_9

Пример 2:

read: element_7
read: element_8
read: element_9
read: element_10

Пример 3:

read: element_2
read: element_8

Кто-нибудь знает, что здесь происходит?

Ответы [ 2 ]

3 голосов
/ 07 сентября 2011

Вы вызываете read и фиксируете возвращаемое значение, но затем вы в значительной степени игнорируете его; он говорит вам, сколько допустимых байтов содержится в readbuffer, но вы обрабатываете readbuffer, как если бы оно содержало строку с нулевым символом в конце, что необязательно. Фактически, один read может давать вам несколько строк с нулевым завершением, если ваш процесс записи данных отправляет 0 байтов через канал; использование printf означает, что вы игнорируете второй и последующие. По крайней мере, вам нужно будет использовать fwrite, чтобы записать конкретное, правильное количество байтов в стандартный вывод, хотя я подозреваю, что на самом деле вам нужно будет заменить эти нули сначала символами новой строки. Возможно, было бы лучше изменить generate_data для отправки новых строк вместо нулей.

0 голосов
/ 07 сентября 2011

Чтение не останавливается на нулевом символе, вы можете прочитать два «сообщения» за один вызов read (). Таким образом, ваш читатель должен проверить, есть ли больше данных после первых 0 (но в пределах n прочитанных байтов), и сохранить их. Следующий вызов чтения должен добавить свои данные к этому остатку. Особый случай - когда в буфере есть оставшееся, но еще не завершенное сообщение.

...