Может ли труба в Linux потерять данные?
И есть ли верхний предел того, сколько данных он может содержать?
Ответы
Ответ 1
Запрет сбоя машины, он не может потерять данные. Это легко неправильно использовать и думать, что вы теряете данные, однако, потому что в записи не удалось записать все запрошенные вами данные, и вы не проверили возвращаемое значение или что-то не так с прочитанным.
Максимальный объем данных, которые он может хранить, зависит от системы - если вы попытаетесь написать больше, вы либо получите короткую запись, либо писатель будет блокироваться до тех пор, пока не будет доступно пространство. На странице руководства pipe(7)
содержится много полезной информации о трубах, в том числе (по крайней мере, на Linux), насколько велик буфер. Linux имеет буферы 4K или 64K в зависимости от версии.
изменить
Тим упоминает SIGPIPE, что также является потенциальной проблемой, которая может потерять данные. Если считыватель закрывает трубку перед чтением всего в ней, непрочитанные данные будут выброшены, и писатель получит сигнал SIGPIPE, когда они пишут больше или закрывают трубку, указывая, что это произошло. Если они блокируют или игнорируют SIGPIPE, они получат ошибку EPIPE. Это касается ситуации, о которой говорил Павел.
PIPE_BUF
- это константа, которая сообщает вам предел атомной записи в буфер. Любая запись такого размера или меньше будет либо полностью завершена, либо заблокирована, пока она не сможет полностью преуспеть (или дать EWOULDBLOCK/EAGAIN, если труба находится в режиме без блокировки). Он не имеет отношения к фактическому размеру буфера канала ядра, хотя, очевидно, буфер должен быть не менее PIPE_BUF по размеру, чтобы соответствовать аутоантитатору.
Ответ 2
Данные могут быть потеряны в трубе, когда происходит следующее:
- Процесс (писатель) записывает n байтов данных в канал, где n≤
PIPE_BUF
. Эта запись гарантированно будет атомарной и никогда не будет блокироваться.
- Процесс (считыватель) считывает только m < n байтов данных и выходов.
- Писатель не пытается снова записать в трубку.
В результате буфер буфера ядра будет содержать n-m байтов, которые будут потеряны, когда все дескрипторы канала будут закрыты. Писатель не увидит SIGPIPE
или EPIPE
, так как он никогда не пытается записать в трубу снова. Поскольку автор никогда не узнает, что труба содержит оставшиеся данные, которые просто исчезнут, можно считать, что эти данные потеряны.
Нестандартным способом обнаружения этого было бы для писателя определить тайм-аут и вызвать FIONREAD
ioctl, чтобы определить количество байтов, оставшихся в буфере канала.
Ответ 3
Если вы ссылаетесь на использование оператора |
в оболочке, то нет, он не потеряет данные. Он просто подключает приложение к стандартному потоку вывода левой стороны к приложению в стандартном потоке ввода справа. Если вы передаете данные между приложениями и не получаете ожидаемых результатов, попробуйте использовать >
для перенаправления стандартного вывода из первого приложения в файл, а затем используйте <
для использования этого файла в качестве стандартного ввода для второго приложения, Таким образом, вы можете проверить файл amd, убедитесь, что данные отправляются в ожидаемом формате.
Если вы имеете в виду канал, созданный функцией pipe
, тогда ответа по-прежнему нет. Согласно эта страница руководства, запись в полный канал будет заблокирована до тех пор, пока не будет прочитано достаточно данных, чтобы освободить место для записи данных. В нем также указывается, что размер канала составляет 4 КБ в Linux до 2.6.11 и составляет 64 КБ на 2.6.11 и более поздних версиях.
Ответ 4
Ваша труба не теряет данные. Если вы теряете данные в своем приложении, попробуйте отладить его с помощью gdb.
Несколько вещей, которые нужно искать:
1) Является ли ваш буфер достаточно большим для хранения всех данных, которые вы читаете?
2) Проверьте коды возврата из вашего read() на трубе для ошибок.
3) Вы уверены, что записываете все данные в трубу?
4) Прерывается ли ваша операция записи/чтения сигналом? т.е.: SIGPIPE?
Ответ 5
Причина, по которой вы не потеряете данные, заключается в том, что когда буфер, связанный с каналом, заполняет вызов write
, будет блокироваться до тех пор, пока читатель не очистит буфер, достаточный для завершения операции. (Вы также можете делать неблокирующие записи, но тогда вы несете ответственность за то, чтобы завершить записи, которые заблокировали бы.)