Может ли канал в Linux когда-либо потерять данные? - PullRequest
14 голосов
/ 26 апреля 2010

И есть ли верхний предел того, сколько данных он может содержать?

Ответы [ 5 ]

21 голосов
/ 26 апреля 2010

Запретить сбой машины, нет, она не может потерять данные. Однако легко использовать его неправильно и думать, что вы теряете данные, либо потому, что при записи не удалось записать все запрошенные вами данные, а вы не проверили возвращаемое значение или сделали что-то не так с чтением.

Максимальный объем данных, который он может хранить, зависит от системы - если вы попытаетесь записать больше, вы получите короткую запись, или устройство записи заблокируется, пока не освободится место. Страница man pipe(7) содержит много полезной информации о каналах, включая (по крайней мере, в Linux) размер буфера. Linux имеет буферы 4K или 64K в зависимости от версии.

редактировать

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

PIPE_BUF - это константа, которая сообщает вам предел атомарных записей в буфер. Любая запись этого размера или меньше будет либо полностью успешной, либо заблокированной, пока не получится полностью (или выдаст EWOULDBLOCK / EAGAIN, если канал находится в неблокирующем режиме). Он не имеет никакого отношения к фактическому размеру конвейерного буфера ядра, хотя очевидно, что размер буфера должен быть не менее PIPE_BUF, чтобы соответствовать гарантии атомарности.

3 голосов
/ 14 марта 2017

Данные могут быть потеряны в канале, когда происходит следующее:

  1. Процесс (писатель) записывает n байт данных в канал, где n≤ PIPE_BUF. Эта запись гарантированно будет атомарной и никогда не заблокируется.
  2. Процесс (читатель) читает только m
  3. Автор не пытается снова записать в канал.

В результате буфер канала ядра будет содержать n-m байтов, которые будут потеряны, когда все дескрипторы канала будут закрыты. Автор не увидит SIGPIPE или EPIPE, поскольку он никогда не попытается снова записать в канал. Поскольку писатель никогда не узнает, что канал содержит оставшиеся данные, которые просто исчезнут, можно считать эти данные потерянными.

Нестандартным способом обнаружения этого было бы, чтобы писатель определял время ожидания и вызывал ioctl FIONREAD, чтобы определить количество байтов, оставшихся в буфере канала.

2 голосов
/ 26 апреля 2010

Ваш канал не теряет данные.Если вы теряете данные в своем приложении, попробуйте отладить их с помощью gdb.Несколько вещей, чтобы искать:1) Достаточно ли велик ваш буфер для хранения всех данных, которые вы читаете?2) Проверьте коды возврата из вашего read () на конвейере на наличие ошибок.3) Вы уверены, что записываете все данные в канал?4) Ваша операция записи / чтения прерывается сигналом?т.е.: SIGPIPE?

2 голосов
/ 26 апреля 2010

Если вы имеете в виду использование оператора | в оболочке, то нет, данные не будут потеряны. Он просто соединяет приложение в стандартном потоке вывода с левой стороны с приложением в стандартном потоке ввода с правой стороны. Если вы передаете данные между приложениями и не получаете ожидаемых результатов, попробуйте использовать >, чтобы перенаправить стандартный вывод из первого приложения в файл, а затем использовать <, чтобы использовать этот файл в качестве стандартного ввода для второго приложения. , Таким образом, вы можете проверить файл и убедиться, что данные отправляются в ожидаемом формате.

Если вы имеете в виду трубу, созданную функцией pipe, то ответ по-прежнему нет. Согласно этой справочной странице , запись в полный канал будет блокироваться до тех пор, пока не будет прочитано достаточно данных, чтобы освободить место для записи данных. В нем также указывается, что размер канала составляет 4 КБ в Linux до 2.6.11 и 64 КБ в 2.6.11 и более поздних версиях.

1 голос
/ 26 апреля 2010

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

...