Я хочу разобрать /proc/net/tcp/
, но это безопасно?
Как мне открывать и читать файлы /proc/
и не бояться, что какой-то другой процесс (или сама ОС) изменит его одновременно?
sysctl
помочь мне /proc/net/tcp/
, например, разобрать файл?
Я хочу разобрать /proc/net/tcp/
, но это безопасно?
Как мне открывать и читать файлы /proc/
и не бояться, что какой-то другой процесс (или сама ОС) изменит его одновременно?
sysctl
помочь мне /proc/net/tcp/
, например, разобрать файл?
Ответы:
В общем нет. (Таким образом, большинство ответов здесь неправильные.) Это может быть безопасно, в зависимости от того, какое свойство вы хотите. Но это может привести к ошибкам в вашем коде, если вы слишком много думаете о согласованности файла в /proc
. Например, посмотрите на эту ошибку, предположив, что это /proc/mounts
был непротиворечивый снимок .
Например:
/proc/uptime
является полностью атомным , а кто - то упомянул в другом ответе , - но только с Linux 2.6.30 , которая составляет менее двух лет. Таким образом, даже этот крошечный, тривиальный файл до тех пор находился в состоянии состязания и все еще находится в большинстве корпоративных ядер. Смотрите fs/proc/uptime.c
текущий источник, или коммит, который сделал его атомарным . В ядре, предшествующем 2.6.30, вы можете немного получить open
файл, read
а затем, если вы потом вернетесь снова и read
снова, полученный вами фрагмент будет несовместим с первым фрагментом. (Я только что продемонстрировал это - попробуйте сами для удовольствия.)
/proc/mounts
является атомарным в пределах одного read
системного вызова. Таким образом, если вы read
весь файл целиком за раз, вы получите один непротиворечивый снимок точек монтирования в системе. Однако, если вы используете несколько read
системных вызовов - и если файл большой, это именно то, что произойдет, если вы используете обычные библиотеки ввода-вывода и не обращаете особого внимания на эту проблему - вы будете подвергаться гонке состояние. Вы не только не получите непротиворечивый снимок, но и точки монтирования, которые присутствовали до того, как вы начали и никогда не прекращали присутствовать, могут пропасть в том, что вы видите. Для того, чтобы увидеть , что это атомное для одного read()
, взглянуть на m_start()
вfs/namespace.c
и увидеть его захватить семафор , который охраняет список точек монтирования, которые он держит до тех пор m_stop()
, что называется , когдаread()
сделано. Чтобы увидеть, что может пойти не так, посмотрите эту ошибку прошлого года (ту же, что я упомянул выше) в другом высококачественном программном обеспечении, которое читается беспечно /proc/mounts
.
/proc/net/tcp
о котором вы на самом деле спрашиваете, даже менее последовательный, чем этот. Это атомарно только в каждом ряду таблицы . Чтобы убедиться в этом, посмотрите на listening_get_next()
вnet/ipv4/tcp_ipv4.c
и established_get_next()
чуть ниже в том же файле, и увидеть замки , они вывозят на каждой записи в очереди. У меня нет удобного кода воспроизведения, чтобы продемонстрировать отсутствие согласованности от строки к строке, но там нет блокировок (или чего-либо еще), которые бы делали его согласованным. Что имеет смысл, если задуматься - сетевое взаимодействие часто является очень загруженной частью системы, поэтому не стоит тратить время на представление единого представления в этом диагностическом инструменте.
Другая часть , которая удерживает /proc/net/tcp
атомную в каждой строке является буферизацией seq_read()
, которые вы можете прочитать вfs/seq_file.c
. Это гарантирует, что после того, как вы read()
войдете в одну строку, текст всей строки будет сохранен в буфере, так что следующий read()
получит оставшуюся часть этой строки перед началом новой. Тот же механизм используется /proc/mounts
для сохранения атомарности каждой строки, даже если вы делаете несколько read()
вызовов, и это также механизм, который используется /proc/uptime
в более новых ядрах, чтобы оставаться атомарным. Этот механизм не буферизирует весь файл, потому что ядро осторожно относится к использованию памяти.
Большинство файлов /proc
будут, по крайней мере, такими же непротиворечивыми, как /proc/net/tcp
и каждая строка с непротиворечивым изображением одной записи в любой предоставляемой ими информации, потому что большинство из них используют одну и ту же seq_file
абстракцию. Однако, как /proc/uptime
показывает пример, некоторые файлы все еще переносились для использования seq_file
в 2009 году; Бьюсь об заклад, есть некоторые, которые используют старые механизмы и даже не имеют такого уровня атомарности. Эти предостережения редко документируются. Для данного файла ваша единственная гарантия - прочитать исходный текст.
В случае /proc/net/tcp
, вы можете прочитать и проанализировать каждую строку без страха. Но если попытаться сделать какие - либо выводы из нескольких строк сразу - берегитесь, другие процессы и ядро являются изменения, пока вы читаете это, и вы, вероятно , создает ошибку.
clock_gettime(2)
с CLOCK_MONOTONIC
(хотя , возможно , есть формальность я не знаю здесь , но лично я только видел его , так как время загрузки). Для Linux у вас также есть возможность sysinfo(2)
.
Хотя файлы /proc
отображаются в виде обычных файлов в пользовательском пространстве, они не являются на самом деле файлами , но вместо лица, поддерживающие стандартные операции с файлами из пользовательского пространства ( open
, read
, close
). Обратите внимание, что это сильно отличается от наличия обычного файла на диске, который изменяется ядром.
Все, что делает ядро, это печатает свое внутреннее состояние в своей собственной памяти, используя sprintf
функцию, подобную функции, и эта память копируется в пространство пользователя всякий раз, когда вы выполняете read(2)
системный вызов.
Ядро обрабатывает эти вызовы совершенно иначе, чем для обычных файлов, что может означать, что весь моментальный снимок данных, которые вы будете читать, может быть готов к тому времени, когда вы open(2)
его обрабатываете , в то время как ядро гарантирует, что одновременные вызовы являются согласованными и атомарными. Я нигде этого не читал, но на самом деле не имеет смысла быть иначе.
Мой совет - взгляните на реализацию файла proc в вашем конкретном варианте Unix. Это действительно проблема реализации (как и формат и содержимое вывода), которая не регулируется стандартом.
Простейшим примером будет реализация uptime
файла proc в Linux. Обратите внимание, как весь буфер создается в функции обратного вызова, предоставленной для single_open
.
proc
файлы - это обычные файлы, открытые для записи ядром.
open()
неверно для многих файлов, и в частности для того /proc/net/tcp
, что касается OP. Это имеет смысл, если вы задумываетесь о стоимости предоставления этой семантики - вам нужно что-то сделать, например, заблокировать внутренние структуры данных, которые записывают все эти соединения TCP, что в загруженной системе является катастрофой, даже если вы удерживаете ее долго достаточно для сканирования и форматирования данных в буфер. Смотрите мой ответ для деталей о том, что на самом деле происходит.
/ proc - это виртуальная файловая система: фактически она просто предоставляет удобное представление о внутренностях ядра. Это определенно безопасно читать (вот почему это здесь), но это рискованно в долгосрочной перспективе, так как внутренняя часть этих виртуальных файлов может развиваться с более новой версией ядра.
РЕДАКТИРОВАТЬ
Более подробную информацию можно найти в документации по proc в документации ядра Linux , глава 1.4. Сеть Я не могу найти информацию о том, как информация эволюционирует с течением времени. Я думал, что это было заморожено на открытом воздухе, но не может быть определенного ответа.
EDIT2
Согласно Sco Doc (не Linux, но я уверен, что все разновидности * nix ведут себя так)
Хотя состояние процесса и, следовательно, содержимое файлов / proc могут меняться от момента к моменту, одно чтение (2) файла / proc гарантирует возвращение «нормального» представления состояния, то есть чтение будет атомный снимок состояния процесса. Такая гарантия не распространяется на последовательные операции чтения, применяемые к файлу / proc для работающего процесса. Кроме того, атомарность специально не гарантируется для любого ввода-вывода, применяемого к файлу as (address-space); содержимое адресного пространства любого процесса может быть одновременно изменено LWP этого процесса или любым другим процессом в системе.
proc
как если бы он имел схожее поведение между различными ядрами (или даже предполагать, что он существует - это не обязательно в Unix-системе). ) принесет вам мир боли.
/proc/net/tcp
, что является главной заботой ОП. Скорее, только каждая отдельная строка в выводе является атомарной. Смотрите мой ответ для деталей.
API procfs в ядре Linux предоставляет интерфейс, который гарантирует, что чтение возвращает согласованные данные. Прочитайте комментарии в __proc_file_read
. Пункт 1) в большом блоке комментариев поясняет этот интерфейс.
Это, как говорится, конечно, до реализации конкретного файла proc, чтобы правильно использовать этот интерфейс, чтобы убедиться, что его возвращенные данные согласованы. Итак, чтобы ответить на ваш вопрос: нет, ядро не гарантирует согласованность файлов proc во время чтения, но предоставляет средства для реализации этих файлов для обеспечения согласованности.
/proc
на самом деле не обеспечивают согласованность. Смотрите мой ответ для деталей.
__proc_file_read()
не рекомендуется в пользу seq_file
. Посмотрите довольно раздраженный комментарий (от Линуса) чуть выше длинного блочного комментария.
У меня под рукой есть исходник для Linux 2.6.27.8, так как я сейчас занимаюсь разработкой драйверов для встроенной цели ARM.
Файл ... linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
в строке 934 содержит, например,
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
i, src, srcp, dest, destp, sp->sk_state,
atomic_read(&sp->sk_wmem_alloc),
atomic_read(&sp->sk_rmem_alloc),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
какие выводы
[wally@zenetfedora ~]$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299
1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299
...
в функции, raw_sock_seq_show()
которая является частью иерархии функций обработки procfs . Текст не генерируется до тех пор, пока не read()
будет сделан запрос к /proc/net/tcp
файлу, что является разумным механизмом, поскольку чтение procfs , безусловно, гораздо реже, чем обновление информации.
Некоторые драйверы (например, мой) реализуют функцию proc_read с одним sprintf()
. Дополнительной сложностью в реализации драйверов ядра является обработка потенциально очень длинных выходных данных, которые могут не помещаться в промежуточный буфер пространства ядра во время одного чтения.
Я проверил это с помощью программы, использующей буфер чтения 64K, но в моей системе буфер пространства в 3072 байта для proc_read возвращал данные. Многократные вызовы с продвигающимися указателями необходимы, чтобы получить больше, чем столько возвращаемого текста. Я не знаю, как правильно сделать согласованные возвращаемые данные, когда требуется более одного ввода-вывода. Конечно, каждая запись /proc/net/tcp
является самосогласованной. Существует некоторая вероятность того, что линии бок о бок снимки в разное время.
ifstream
, это будет небезопасно, но если я буду использовать read
это будет безопасно? Или ifstream
использует внутренне read
? А что ты предлагаешь?
/proc/net/tcp
форматируются и полностью не зависит от того, как их читают.
/proc/net/tcp
) не приходят из одного и того же снимка. Смотрите мой ответ для некоторых объяснений.
Если не считать неизвестных ошибок, нет никаких условий гонки /proc
, которые привели бы к чтению поврежденных данных или смеси старых и новых данных. В этом смысле это безопасно. Однако все еще существует условие, что большая часть данных, которые вы читаете, /proc
потенциально устарела, как только она сгенерирована, и тем более к тому времени, когда вы приступите к ее чтению / обработке. Например, процессы могут умереть в любое время, и новому процессу может быть назначен тот же pid; единственные идентификаторы процессов, которые вы можете использовать без условий гонки, - это ваши собственные дочерние процессы ». То же самое касается сетевой информации (открытые порты и т. Д.) И действительно большей части информации в /proc
. Я бы посчитал плохой и опасной практикой полагаться на любые данные в/proc
быть точным, за исключением данных о вашем собственном процессе и, возможно, его дочерних процессах. Конечно, все еще может быть полезно представить другую информацию /proc
пользователю / администратору для информативности / регистрации / и т.д. цели.
getpid()
). Так что это должно быть безопасно.
/proc
интерфейса, все они имеют одинаковые недостатки и сильные стороны. В любом случае, OP запрашивает информацию о драйвере устройства, а не о процессах.
N
- ваш дочерний процесс, вы можете убедиться, что pid по- N
прежнему ссылается на тот же (возможно, завершенный) процесс, пока вы не wait
вызовете для него функцию -family. Это гарантирует, что нет гонок.
Когда вы читаете из файла / proc, ядро вызывает функцию, которая была заранее зарегистрирована, чтобы быть функцией «чтения» для этого файла proc. Смотрите __proc_file_read
функцию в fs / proc / generic.c.
Таким образом, безопасность чтения процесса является такой же безопасной, как и функция, вызываемая ядром для удовлетворения запроса на чтение. Если эта функция правильно блокирует все данные, к которым она прикасается, и возвращает их в буфер, тогда ее использование полностью безопасно для чтения. Поскольку файлы proc, подобные тем, которые использовались для удовлетворения запросов на чтение в / proc / net / tcp, существуют уже некоторое время и проходят тщательную проверку, они настолько безопасны, насколько вы можете просить. Фактически, многие распространенные утилиты Linux полагаются на чтение из файловой системы proc и форматирование вывода другим способом. (Я думаю, что «ps» и «netstat» делают это).
Как всегда, вы не должны поверить на мое слово; Вы можете посмотреть на источник, чтобы успокоить свои страхи. Следующая документация из proc_net_tcp.txt сообщает вам, где находятся функции «чтения» для / proc / net / tcp, так что вы можете посмотреть на реальный код, который запускается при чтении из этого файла proc, и убедиться в том, что нет блокировка опасностей.
Этот документ описывает интерфейсы / proc / net / tcp и / proc / net / tcp6.
Обратите внимание, что эти интерфейсы устарели в пользу tcp_diag. Эти интерфейсы / proc предоставляют информацию о текущих активных TCP-соединениях и реализуются с помощью tcp4_seq_show () в net / ipv4 / tcp_ipv4.c и tcp6_seq_show () в net / ipv6 / tcp_ipv6.c соответственно.