Как закрыть дескриптор файла с помощью команды оболочки Linux

В /proc/pid/fd/ слишком много файловых дескрипторов. Могу ли я использовать команду оболочки, чтобы закрыть эти файловые дескрипторы?


person Eric    schedule 13.05.2011    source источник
comment
Какой это процесс? Это ваша программа? Можете ли вы опубликовать какой-нибудь источник?   -  person MarkR    schedule 14.05.2011
comment
У меня был случай, когда какое-то коммерческое приложение открыло один и тот же файл с более чем 1000 файловых дескрипторов, а затем закончились файловые дескрипторы. Приложение даже не могло завершиться своими собственными командами, поэтому мне пришлось его убить. Если бы мне удалось закрыть некоторые файловые дескрипторы, возможно, программа завершилась бы более аккуратно.   -  person U. Windl    schedule 06.02.2019


Ответы (5)


Вы определенно можете закрыть fd других запущенных процессов, если у вас есть на это права.

Сначала найдите PID.

Затем запустите gdb и присоединитесь к процессу:

gdb -p 1598

Затем вызовите системный вызов close для файла fd, который вы хотите закрыть:

(gdb) call close(999)
$1 = 0

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

person Thomas Vander Stichele    schedule 21.08.2012

Вы можете закрыть FD n текущего процесса в bash следующим образом:

exec n<&-
person Ignacio Vazquez-Abrams    schedule 13.05.2011
comment
Спасибо. Но он используется для закрытия FD текущего процесса (процесса bash). Знаете ли вы какой-либо способ закрыть FD конкретного процесса? - person Eric; 13.05.2011

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

Поэтому я придумал быстрое правило iptables. Необязательные аргументы заключены в квадратные скобки ([ opt ]).

  1. Найдите адрес и порт назначения:

    netstat --program [ --numeric-host --numeric-ports ] | grep [<pid>]/[<appname>]

    $ netstat --program --numeric-ports | grep 8812/
    tcp        0      0 ysc.xxx:54055          10.56.1.152:30000           ESTABLISHED 8812/my-application
    tcp        0      0 ysc.xxx:46786          postgres.xxx:5432           ESTABLISHED 8812/my-application
    tcp        0      0 ysc.xxx:36090          10.56.4.79:57000            ESTABLISHED 8812/my-application
                                          ...
    unix  2      [ ]         DGRAM                    7177020 8812/my-application
    

    Здесь я хотел бы вырезать 10.56.4.79:57000.

  2. Создайте правило iptables для обрезания сокета:

    iptables -A OUTPUT [ --out-interface <if> --protocol <tcp|udp|unix> ] --destination <addr> --dport <port> --jump DROP

    $ iptables -A OUTPUT --destination 10.56.4.79 --dport 57000 --jump DROP
    $
    
  3. На данном этапе ваша программа не может отправлять пакеты на удаленный хост. В большинстве случаев TCP-соединение закрывается. Вы можете продолжить свои тесты, если они есть.

    $ netstat --program --numeric-ports | grep 8812/
    tcp        0      0 ysc.xxx:54055          10.56.1.152:30000           ESTABLISHED 8812/my-application
    tcp        0      0 ysc.xxx:46786          postgres.xxx:5432           ESTABLISHED 8812/my-application
                                          ...
    unix  2      [ ]         DGRAM                    7177020 8812/my-application
    
  4. Удалите правило iptables:

    Вы просто вводите то же правило iptables, заменяя A на D.

    $ iptables -D OUTPUT --destination 10.56.4.79 --dport 57000 --jump DROP
    $
    
person YSC    schedule 23.02.2016
comment
Обратите внимание, что я намеревался проверить, как мое приложение отреагирует, если потеряет соединение с критически важной службой. - person YSC; 23.02.2016
comment
Вопрос был общим для файловых дескрипторов; ваш ответ только для сетевых подключений. И самое главное, он не закрывает дескриптор файла; он просто отбрасывает сетевой трафик. - person U. Windl; 06.02.2019
comment
@U.Windl Если ваше приложение ведет себя правильно, это приводит к завершению этого TCP-соединения и дескриптора файла. Как я уже сказал в своем ответе, в большинстве случаев TCP-соединение закрыто. Это не панацея, но если это может помочь людям... - person YSC; 06.02.2019
comment
Только если в TCP используется опция поддержки активности: в противном случае мертвые соединения могут оставаться там до закрытия или сброса. - person U. Windl; 11.02.2019
comment
Возможно, это не был ответ на заданный вопрос, но это помогло мне сделать то, что я пытался сделать. - person John Ilacqua; 01.04.2019

Ответ @Thomas действителен только в том случае, если установлена ​​отладочная информация для вызова close().

Без установленной отладочной информации gdb отказывается вызывать close():

(gdb) call close(3)
'close' has unknown return type; cast the call to its declared return type

Самый простой способ заставить gdb вызывать close() в этом случае — привести вызов к возвращаемому типу close():

(gdb) call (int)close(3)
$1 = 0

См. gdb документацию:

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

Для прототипированных (т. е. в стиле ANSI/ISO) функций есть два способа сделать это. Самый простой — привести вызов к объявленному возвращаемому типу функции.

person ks1322    schedule 15.11.2018
comment
Вероятно, из-за агрессивного современного удаления таблицы символов: close() является системным вызовом, и он должен быть известен любому процессу, использующему разделяемую библиотеку C. - person U. Windl; 06.02.2019

Вы не можете просто закрыть файловые дескрипторы других процессов и ожидать, что они продолжат работать.

Исправьте программу, в которой открыто слишком много файлов, чтобы она открывалась меньше. Это может быть изменение конфигурации или изменение источника и т. д. Вы не можете просто закрыть файлы для этого.

person MarkR    schedule 14.05.2011
comment
Что вы можете. Обычным случаем такого желания является то, что программа пропускает fd; в этом случае он никогда не будет использовать их снова. Конечно, это ошибка, но желание ее обойти все же имеет смысл. - person Thomas Vander Stichele; 21.08.2012
comment
В моем случае у меня был длительный зависший пакетный процесс, потому что чтение из http-сокета умерло. Закрытие fd, как описал @ThomasVanderStichele, решило проблему для меня :-) - person Chris Withers; 31.03.2015
comment
А что, если у вас нет доступа к исходному коду программы? - person klutt; 11.09.2019