Закрытие порта вручную из командной строки

369921
Glorfindel

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

Есть ли какая-либо опция командной строки в Linux для закрытия порта?

ПРИМЕЧАНИЕ: я узнал, что «только приложение, которому принадлежит подключенный сокет, должно закрывать его, что произойдет, когда приложение завершится».

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

95
Нет, открытые порты * принадлежат * процессу, который их открыл, контроль извне невозможен. Что хорошо, иначе все приложения должны будут ожидать, что их открытые порты (и файлы) будут испорчены. Однако вы можете заблокировать трафик к порту с помощью брандмауэра (iptables), но это не закроет и не даст порт для другого использования. Jürgen Strobel 12 лет назад 5
Многие респонденты не поняли смысл этого вопроса. Бессмысленно заявлять, что только приложение, которому принадлежит порт, может отключить его. Я могу отключить его, подойдя к коробке и вытащив кабель Ethernet из розетки, или убив приложение на другом конце соединения! Приложение должно быть написано, чтобы справиться с этим. Итак --- как вы проверяете, чтобы убедиться, что приложение написано правильно, не требуя физического вмешательства и / или контроля над другим компьютером? Dale Wilson 9 лет назад 9
«... контроль извне невозможен». Это важное замечание, которое привело меня к следующему вопросу, как я могу быть частью процесса извне? GDB. Dankó Dávid 5 лет назад 0

13 ответов на вопрос

114
Dankó Dávid

У меня была такая же проблема, процесс должен остаться в живых, но сокет должен закрыться. Закрытие сокета в работающем процессе не является невозможным, но трудным:

  1. найдите процесс:

    netstat -np 

    Вы получаете source/destination ip:port portstate pid/processnameкарту

  2. найдите дескриптор файла сокета в процессе

    lsof -np $pid 

    Вы получаете список: имя процесса, pid, пользователь, fileDescriptor, ... строка подключения.

    Найдите соответствующий номер fileDescriptor для соединения.

    Теперь подключите процесс:

    gdb -p $pid 
  3. Теперь закройте сокет:

    call close($fileDescritor)  //does not need ; at end. 

    Затем отсоедините:

    quit 

    И розетка закрыта.

`sudo lsof -np $ pid` дает мне около 200 строк, и я не совсем понимаю, как найти нужный FD. В моем случае это вкладка Chrome, и я пытаюсь закрыть открытые веб-сокеты ... SET 9 лет назад 1
Строка, как правило, выглядит следующим образом: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) как: имя-процесса pid user fd [open_for] протокол устройства inode protocol_data_toString Dankó Dávid 9 лет назад 2
* Строка, как правило, выглядит следующим образом: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) как: process_name pid user fd [open_for] протокол устройство inode protocol_data_toString ip, который вам необходимо знать адрес и найти на послед. В моем примере 97 - это FileDescriptor. Поиск затруднен, если вы открыли несколько подключений к целевому хосту. Dankó Dávid 9 лет назад 2
это блестящее решение marcorossi 9 лет назад 7
- это действительно спасатель жизни. mik 8 лет назад 0
Если вы хотите смоделировать сокет, закрываемый удаленным концом (например, выход из узла), лучше использовать `shutdown`:` call shutdown ($ fileDescriptor, 0) `. ecatmur 8 лет назад 7
Удивительно, именно то, что мне было нужно. 0atman 7 лет назад 0
Никогда не думал об этом. Мой редис-сервер не принимал никаких подключений. Но мне нужно сохранить это в живых. Это помогло мне решить проблему. * спасатель * Shiplu Mokaddim 7 лет назад 1
Интересно, почему это так круто в Linux. В Windows я могу просто запустить Process Explorer (скачать с веб-сайта MS), просмотреть список дескрипторов для каждого процесса и закрыть их один за другим с помощью мыши. Использование gdb даже приостанавливает работу программы, которая является питой из-за тайм-аутов и т. Д. Mark Jeronimus 6 лет назад 0
У меня есть процесс `node`, работающий с очень длительным тайм-аутом (~ 5 часов), и у меня есть несколько открытых соединений, которые в конечном итоге потерпят неудачу, поэтому я попытался вызвать оба` shutdown` и `close` для каждого из этих сокетов, но процесс продолжал работать заблокирован. Я могу подтвердить из вывода `lsof`, что этих сокетов больше нет. Есть ли что-то еще, что я могу сделать, вместо того, чтобы ждать 5 часов, чтобы время ожидания истекло? haridsv 5 лет назад 0
Ну, я не хочу быть троллем, но в unixes / proc является родным проводником процессов в системе. Однако мы можем создать действительно пустую команду, чтобы закрыть fd процесса: `#! / Bin / bash echo -e" call close ($ 2) \ ndetach \ nquit \ n "| gdb -p $ 1> / dev / null 2> & 1` `close-proc-fd $ pid $ fd`, который можно встроить в бэкэнд приложения. Однако это решение, особенно если вы начнете собирать его как команду, является излишним решением. Dankó Dávid 5 лет назад 0
«Использование gdb даже приостанавливает работу программы», да, к сожалению, в любом случае это происходит (https://stackoverflow.com/questions/9746018/gdb-attach-to-a-process-without-stop), но вы можете продолжить (продолжение) выполнение сразу после прикрепления. Dankó Dávid 5 лет назад 0
74
Guy Avraham

Вы вроде задаете неправильный вопрос здесь. На самом деле просто невозможно «закрыть порт» извне приложения, открывшего сокет, прослушивающий его. Единственный способ сделать это - полностью убить процесс, которому принадлежит порт. Затем, через минуту или две, порт снова станет доступным для использования. Вот что происходит (если вам все равно, перейдите к концу, где я покажу вам, как убить процесс, владеющий конкретным портом):

Порты - это ресурсы, выделяемые ОС различным процессам. Это похоже на запрос ОС к указателю файла. Однако, в отличие от файловых указателей, порт может иметь только ОДИН процесс за раз. Через интерфейс сокета BSD процессы могут сделать запрос на прослушивание порта, который ОС затем предоставит. ОС также будет следить за тем, чтобы другие процессы не получали такой же порт. В любой момент процесс может освободить порт, закрыв сокет. Затем ОС восстановит порт. В качестве альтернативы, если процесс завершится без освобождения порта, ОС в конечном итоге восстановит порт (хотя это произойдет не сразу: это займет несколько минут).

Теперь то, что вы хотите сделать (просто закрыть порт из командной строки), невозможно по двум причинам. Во-первых, если бы это было возможно, это означало бы, что один процесс мог просто украсть ресурс другого процесса (порт). Это было бы плохой политикой, если не ограничено привилегированными процессами. Вторая причина - неясно, что произойдет с процессом, которому принадлежит порт, если мы позволим ему продолжить работу. Код процесса написан в предположении, что он владеет этим ресурсом. Если бы мы просто забрали его, он сам бы закончился сбоем, поэтому ОС не позволяет вам этого делать, даже если вы являетесь привилегированным процессом. Вместо этого вы должны просто убить их.

В любом случае, вот как убить процесс, которому принадлежит определенный порт:

sudo netstat -ap | grep :<port_number> 

Это выведет строку, соответствующую порту удержания процесса, например:

tcp 0 0 *:8000 *:* LISTEN 4683/procHoldingPort 

В этом случае procHoldingPort - это имя процесса, который открыл порт, 4683 - это его pid, а 8000 (обратите внимание, что это TCP) - это номер порта, который он содержит.

Затем посмотрите в последнем столбце, вы увидите /. Затем выполните это:

kill <pid> 

Если это не сработает (вы можете проверить, повторно выполнив команду netstat). Сделай это:

kill -9 <pid> 

В общем, лучше избегать отправки SIGKILL, если можете. Вот почему я говорю вам попробовать killраньше kill -9. Просто использование killпосылает мягче SIGTERM.

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

@smehmood - Спасибо за подробное объяснение .. Небольшое сомнение .. Как ядро ​​восстанавливает открытый порт внезапно убитым процессом ?? ... решение, которое вы предоставили, похоже, убивает процесс, удерживающий порт ... 14 лет назад 0
@codingfreak Ядро знает, что процесс завершен. Он знает, что может восстановить порт. На самом деле есть правила по срокам закрытия порта, чтобы убедиться, что в сети нет плавающих пакетов. Откуда оно знает, что у него есть эти ресурсы? это то, что делает ядро, следит за вещами. Rich Homolka 10 лет назад 3
Пока кто-то не отправит что-нибудь разумное, например, `unix.tools.port.close () `Я бы использовал` init 6`. Snowcrash 7 лет назад 0
18
RedBaron

Фьюзер также может быть использован

fuser -k -n *protocol portno* 

Здесь протокол tcp / udp, а portno - номер, который вы хотите закрыть. Например

fuser -k -n tcp 37 

Больше информации на странице man fuser

Просто убить собственный процесс не сработало для меня, но фьюзер сработал. Спасибо! webwurst 10 лет назад 0
Я получил смешанные результаты с ним, даже после использования fuser, я получил «сокет уже используется» при попытке повторно использовать порт из убитого приложения, даже делая это как root. С другой стороны, время для освобождения розетки оказалось короче, чем раньше, так что в любом случае спасибо. Jan Vlcinsky 10 лет назад 0
@JanVlcinsky Может быть, есть процесс-опекун, который перезапускает убитый процесс через несколько секунд после запуска `fuser`? RedBaron 10 лет назад 0
@RedBaron: согласно комментарию http://superuser.com/a/415236/153413 моя проблема возникает из-за плохо написанного приложения, которое не очищает / не закрывает сокет при завершении. Таким образом, `fuser` находит процесс, используя порт, и убивает его, но не устраняет тот факт, что сокет не закрыт. 60 секунд и ядро ​​делает это для меня. Jan Vlcinsky 10 лет назад 0
5
supercheetah

В качестве альтернативы вы можете использовать iptables:

iptables -I INPUT -p tcp --dport 80 -j DROP 

Это в основном выполняет то, что вы хотите. Это отбросит весь трафик TCP на порт 80.

Нет, это будет держать сокет открытым, пока все таймауты не закроют их. (Он будет скрывать весь трафик от процесса-владельца, который затем не имеет средств знать, что он должен его закрывать.) Вы можете использовать `-j REJECT` для возврата флага сброса TCP, который затем будет виден моему процессу-владельцу (но только когда другая сторона пытается что-то отправить). Marki555 8 лет назад 4
3
Ben
netstat -anp | grep 80 

Он должен сказать вам, если вы используете apache, «httpd» (это только пример, используйте порт, который ваше приложение использует вместо 80)

pkill -9 httpd 

или же

killall -9 httpd 
попробуйте нормальное убийство, прежде чем прибегнуть к -9 Thilo 14 лет назад 3
@omfgroflmao - но это убьет процесс, который открыл порт ?? 14 лет назад 0
@codingfreak Процесс, который удерживает порт, да, он убьет его. 14 лет назад 0
2
jackenheimer

Вы могли бы просто узнать, какой процесс открыл сокет, с которым связан порт, и убить этот процесс.

Но вы должны понимать, что если у этого процесса нет обработчика, который деинициализирует весь используемый им материал (открытые файлы, сокеты, вилки, вещи, которые могут задерживаться, если он не будет закрыт должным образом после завершения), вы бы создали перетащите на производительность системы. Кроме того, сокет будет оставаться открытым, пока ядро ​​не поймет, что процесс был убит. Обычно это занимает около минуты.

Я полагаю, что лучшим вопросом будет: какой порт (принадлежащий к какому процессу) вы хотите остановить?

Если вы пытаетесь положить конец обнаруженному бэкдору или вирусу, то вам следует, по крайней мере, узнать, какие данные передаются взад-вперед, прежде чем уничтожить их. (wireshark хорош для этого) (И имя исполняемого файла процесса, чтобы вы могли удалить его и предотвратить его повторный запуск при перезагрузке) или, если это что-то, что вы установили (например, HTTPD или FTPD или что-то еще), то у вас уже должен быть доступ к сам процесс.

Обычно это будет управляющая программа (HTTPD stop | start или что-то в этом роде). Или, если это системная вещь, вы, вероятно, не должны связываться с ней. Во всяком случае, я подумал, что, поскольку все остальные дают вам угол «как», я должен дать вам предостережения.

Очень хороший комментарий. У меня есть одна программа, которая при закрытии не закрывает сокет, что приводит к описанному поведению - сокет не работает в течение примерно 60 секунд. Когда я останавливаюсь и запускаю этот процесс, он примерно минуту жалуется, что адрес и порт уже используются. Лучшее решение - исправить некорректно закрывающийся процесс, чтобы закрыть его, но иногда это не вариант. Есть ли способ попросить ядро ​​проверить этот заблокированный сокет раньше, чем через 60 секунд? Jan Vlcinsky 10 лет назад 0
2
Alejandro BR

I first looked for the mongo and node processes, then did the following:

ps -A | grep node  10418 pts/23 00:00:05 node  10551 pts/23 00:00:00 node  ps -A | grep mongo  10490 pts/23 00:00:00 mongod 

Once identified, just kill the processes with the kill command.

kill -9 10418 kill -9 10490 

Lastly, type meteor and it should be working again.

1
Michael Shimmins

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

Другие ответы показали вам, как убить процесс, связанный с портом - это может быть не то, что вы хотите. Если вы хотите, чтобы сервер продолжал работать, но для предотвращения соединений с клиентами, то вы хотите заблокировать порт, а не останавливать процесс.

@Michael Shimmins ... хм, звучит интересно, так как мы можем заблокировать порт на стороне сервера, чтобы клиент не отправлял никаких сообщений. 14 лет назад 0
Ну, клиент может отправлять сообщения все, что они хотят, мы просто закрыли дверь, чтобы они не могли войти. 14 лет назад 0
1
Rich Homolka

Еще одна проблема: иногда ядру принадлежат сами порты. Я знаю, что NAT-маршрутизация держит некоторые порты открытыми для использования NAT. Вы не можете убить процесс для этого, это ядро, и требуется перенастройка и перезагрузка.

1
Daniel

If you want your port to be released sooner, you have to set the following value:

echo 1 > /proc/sys/net/ipv4/tcp_fin_timeout 

to set it from 60 seconds (default) to 1 second

Похожие вопросы