題 從命令行手動關閉端口


我想關閉一個在我的客戶端和服務器應用程序之間處於偵聽模式的開放端口。

Linux中是否有任何手動命令行選項來關閉端口?

注意:  我開始知道“只有擁有連接套接字的應用程序應該關閉它,這將在應用程序終止時發生。”

我不明白為什麼它只能通過打開它的應用程序...但我仍然渴望知道是否還有其他方法可以做到這一點。


95
2018-04-06 03:39


起源


不,打開港口 屬於 對於打開它們的過程,無法從外部進行控制。這是一件好事,或者所有應用程序都必須預測他們的開放端口(和文件)被搞砸了。但是,您可以通過防火牆(iptables)阻止到端口的流量,但這不會關閉並放棄該端口以供其他用途。 - Jürgen Strobel
很多響應者都錯過了這個問題。聲明只有擁有該端口的應用程序才能斷開它是無稽之談。我可以通過走到盒子並將以太網電纜從插座中拉出來,或者通過殺死連接另一端的應用程序來斷開它!必須編寫應用程序來處理此問題。那麼---你如何測試以確保應用程序是否正確編寫而無需對其他計算機進行物理干預和/或控制? - Dale Wilson
“......外面無法控制。”這是一個重要的評論,這引導我進入下一個問題,我如何能夠從外部成為流程的一部分? GDB。 - 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
    

    插座已關閉。


114
2017-11-01 01:43



sudo lsof -np $pid 給了我大約200行,我很困惑如何找到所需的FD。在我的情況下,進程是一個Chrome選項卡,我正在嘗試關閉打開的websockets ... - SET
一行通常看起來像:firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https(ESTABLISHED)as:process_name pid user fd [opened_for] protocol device inode protocol_data_toString - Dankó Dávid
*行通常看起來像:firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https(ESTABLISHED)as:process_name pid用戶fd [opened_for]協議設備inode protocol_data_toString你需要知道遠程ip地址並找到最後一個col。在我的例子中,97是FileDescriptor。如果打開與目標主機的多個連接,則搜索很困難。 - Dankó Dávid
這是一個很棒的解決方案 - marcorossi
如果您想模擬遠程端關閉的套接字(例如,對等端退出),最好使用它 shutdown: call shutdown($fileDescriptor, 0)。 - ecatmur


你在這裡問錯了問題。實際上不可能簡單地從打開監聽套接字的應用程序外部“關閉端口”。執行此操作的唯一方法是完全終止擁有該端口的進程。然後,在大約一兩分鐘內,端口將再次可用。這是正在發生的事情(如果你不在乎,跳到最後我向你展示如何殺死擁有特定端口的進程):

端口是操作系統分配給不同進程的資源。這類似於向操作系統詢問文件指針。但是,與文件指針不同,一次只有一個進程可能擁有一個端口。通過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。

就像我說的那樣,如果這樣做,端口重新打開仍需要幾分鐘時間。我不知道如何加快這個速度。如果其他人這樣做,我很樂意聽到。


74
2018-04-06 04:05



@smehmood - 感謝您的詳細解釋..一個小疑問..內核如何通過突然殺死進程回收開放端口? ..你提供的解決方案似乎正在殺死持有端口的進程...
@codingfreak內核知道進程消失了。它知道它可以收回港口。關閉端口的時間實際上有規則,以確保沒有任何雜散數據包漂浮在網絡上。它如何知道它有這些資源?這就是內核的作用,跟踪事物。 - Rich Homolka
直到某人發布了一些明智的東西 unix.tools.port.close(<my port number>) 我會用 init 6。 - Snowcrash


也可以使用定影器

fuser -k -n *protocol portno*

這裡的協議是tcp / udp,portno是你想要關閉的號碼。 例如。

fuser -k -n tcp 37

更多信息在 熱熔器手冊頁


18
2018-02-13 08:44



只是殺死擁有過程並不適合我,但是熱熔器確實如此。謝謝! - webwurst
我得到了混合的結果,即使在使用熱熔器之後,當嘗試重用來自kill app的端口時,我得到了“套接字已經在使用”,甚至以root用戶身份執行。另一方面,釋放插座的時間似乎比之前更短,所以無論如何,謝謝。 - Jan Vlcinsky
@JanVlcinsky也許有一個“守護者”進程,在此之後重新啟動被殺死的進程 fuser 跑? - RedBaron
@RedBaron:據評論 superuser.com/a/415236/153413 我的問題源於寫得不好的應用程序,它不會在終止時清理/關閉套接字。所以 fuser 使用端口查找進程並將其終止,但不解決套接字未關閉的事實。 60秒,內核為我做了。 - Jan Vlcinsky


你也可以使用iptables:

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

它基本上可以實現你想要的。這會將所有TCP流量丟棄到端口80。


5
2018-04-06 09:38



不,這將保持套接字打開,直到所有超時關閉它們。 (它將隱藏來自擁有進程的所有流量,然後無法知道它應該關閉它。)你可以使用 -j REJECT 返回TCP重置標誌,然後可以看到我的擁有過程(但只有當另一方嘗試發送內容時)。 - Marki555


netstat -anp | grep 80

它應該告訴你,如果你正在運行apache,“httpd”(這只是一個例子,使用你的應用程序使用的端口代替80)

pkill -9 httpd 

要么

killall -9 httpd

3
2018-04-06 03:45



在訴諸-9之前嘗試正常的殺戮 - Thilo
@omfgroflmao - 但它會殺死已打開端口的進程?
@codingfreak持有端口的進程,是的,它會殺死它。


您可能只是找出哪個進程打開了端口所在的套接字 與該過程相關聯並殺死該過程。

但是,你必須意識到,除非 該進程有一個處理程序,用於解除它正在使用的所有東西(打開 文件,套接字,分叉,除非在終止時正確關閉,否則可以延續的東西 那麼你就會創造出對系統性能的拖累。另外,插座將保留 打開,直到內核意識到該進程已被殺死。那通常只是 大約需要一分鐘。

我想更好的問題是:什麼端口(屬於 你想停止什麼過程?

如果你試圖結束後門或 你找到的病毒,那麼你至少應該知道來回傳播的數據 在你終止之前。 (wireshark對此很好)(並且進程'可執行文件名稱,以便您可以刪除它並防止它在重新啟動時返回),或者,如果它是您安裝的東西(如HTTPD或FTPD或其他東西),那麼您應該已經有權訪問過程本身。

通常它會有一個控製程序(HTTPD停止|啟動等)。或者,如果它是一個系統的東西,你可能不應該搞亂它。無論如何,我認為,既然其他人都給你“如何做”的角度,我應該給你一些警告。


2
2018-04-22 05:02



非常好的評論。我有一個程序,在終止時不會關閉套接字會導致所描述的行為 - 套接字無法使用大約60秒。當我停止並啟動該過程時,它抱怨大約一分鐘,地址和端口已經在使用中。最好的解決方案是糾正錯誤的行為以正確關閉,但有時這不是一個選擇。有沒有辦法要求內核檢查比60秒內更快地阻塞套接字? - Jan Vlcinsky


我首先查找mongo和節點進程,然後執行以下操作:

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

一旦確定,只需使用kill命令終止進程。

kill -9 10418
kill -9 10490

最後,輸入 meteor 它應該再次工作。


2
2018-05-27 03:46





您可以編寫一個腳本來修改iptables並重新啟動它們。一個腳本用於添加規則,刪除端口上的所有數據包,另一個腳本用於刪除所述規則。

其他答案向您展示瞭如何殺死綁定到端口的進程 - 這可能不是您想要的。如果您希望服務器繼續運行,但為了阻止來自客戶端的連接,那麼您希望阻止該端口,而不是停止該進程。


1
2018-04-06 04:10



@Michael Shimmins ...聽起來很有趣,因為我們可以阻止服務器端的端口,以便客戶端不會發送任何消息。
那麼客戶端可以發送所有他們想要的消息,我們只是關門,所以他們無法進入。


還有一個問題:有時內核自己擁有端口。我知道NAT路由保持一些端口可供NAT使用。你不能為此殺死進程,這是一個內核,需要重新配置和重新啟動。


1
2017-11-01 02:08





如果希望更快地釋放端口,則必須設置以下值:

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

將其設置為60秒(默認)為1秒


1
2018-04-23 06:06





您可以使用名為killcx的命令,在沒有任何進程的情況下關閉連接。

  • 句法:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • 例:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0

1
2017-07-29 02:25



//,大多數Linux機器都有killcx嗎?我嘗試過的這些都沒有使用這個killcx命令,而沒有使用他們當前的存儲庫配置安裝不可用的包。 - Nathan Basanese
不,你可以在這裡找到這個工具: killcx.sourceforge.net - shuaiming
//,我知道我可以找到這個工具,在數千台服務器上安裝它只是一件痛苦的事。 - Nathan Basanese
使用Puppet @NathanBasanese :) - SHOUBHIK BOSE