如何使用 fuser 識別占用連接埠的行程

當你啟動服務時,終端機卻立刻回傳:address already in use。這表示該連接埠已被其他程式搶先占用,在找到它之前,你的應用程式無法綁定這個連接埠。
在 Linux 上,fuser 是找出繁忙連接埠背後 PID 的最快方法。只需一行命令就能得到答案:執行 fuser -v -n tcp [port],即可查看占用該連接埠的使用者和行程 ID。
假設連接埠 3000 已經被占用。你可以用 fuser 在幾秒鐘內查清楚。本文將向你展示如何找出是誰在使用該連接埠、如何檢查 UDP 連接埠是否已被占用,以及在採取下一步操作之前如何正確解讀輸出結果。
理解 fuser 命令
fuser 的作用及其來源
fuser 是 Linux 上的一個命令列工具,用於識別目前正在使用某個檔案、目錄、socket 或檔案系統的行程。它的名字是 「file user」 的縮寫,這也解釋了它用途廣泛的原因。你可以將它指向一個被鎖定的檔案、一個已掛載的目錄,或者一個網路 socket,它都會告訴你是誰在占用它。根據 Ostechnix 的說法,該工具會提供每個行程的詳細資訊,包括所屬使用者、行程 ID、存取類型以及所使用的命令。
你通常可以在 psmisc 套件中找到 fuser,而大多數 Linux 發行版都會內建該套件。這一點對故障排除非常重要。因為該工具通常已經存在於系統中,所以你無需額外安裝任何新軟體,就能診斷連接埠被占用的問題。Ostechnix 指出,fuser 在檔案鎖定、行程管理和系統資源問題排查方面尤其有用。
用於連接埠檢查的基本語法
-n 參數用於告訴 fuser 要搜尋哪個命名空間,你可以傳入 tcp 或 udp 作為協定。你也可以使用 port/protocol 這種簡寫形式,例如 22/tcp,把連接埠號與協定合併為一個參數。這兩種寫法都可以,選擇你覺得在記錄中更清楚的方式即可。
預設輸出非常精簡。fuser 只會回傳 PID,並以空格分隔,不帶任何標籤。這對腳本很方便,但人眼閱讀並不友善。加上 -v 參數後,你會得到一個更詳細的輸出表,其中包含四欄:
欄位 | 含義 |
|---|---|
USER | 行程的所屬使用者 |
PID | 行程 ID |
ACCESS | 存取類型,例如 f 表示開啟的檔案,c 表示目前目錄 |
COMMAND | 命令名稱 |
詳細輸出真正回答了核心問題:不僅是哪個 PID 占用了連接埠,還包括是哪個使用者、哪個程式。採取操作前,請先讀清楚這一列。
如何使用 fuser 檢查連接埠
識別哪個行程正在監聽某個特定連接埠
先來看一個具體場景。假設某個服務啟動失敗,因為連接埠 8002 已被其他程式占用。執行 fuser -v -n tcp 8002,然後閱讀它列印出的表格。USER 欄顯示擁有該行程的帳號。PID 欄給出你需要的行程 ID。ACCESS 欄說明該行程如何存取這個 socket,其中可能會出現 f 之類的標記,表示它以檔案方式開啟該 socket。COMMAND 欄則顯示程式本身的名稱。
這一列資訊就足夠說明一切:是誰啟動了它、它是什麼程式,以及你接下來該如何處理。你可以用這種方式檢查任意連接埠,通常不到一秒就能得到結果。
簡寫形式的效果完全一樣。你不必分開寫參數,而是可以把連接埠和協定直接寫在一起。VMware Photon 的文件清楚展示了這種寫法:
請把該輸出理解為一份純 PID 清單。左側標籤表示 socket,右側數字則是附著在其上的行程。多個數字說明有多個行程共用同一個 socket,這在會派生多個工作行程的 Web 伺服器中很常見。要找出某個特定連接埠上正在監聽的行程/服務,在大多數情況下你通常只需要第一個數字。
協定非常重要。TCP 檢查不會顯示 UDP 監聽器,反過來也一樣。因此務必讓參數與實際流量類型匹配。如果你不確定,就把兩種都查一遍。這正是在 Linux 中查找哪個行程或服務正在監聽某個特定連接埠的核心習慣:先確認協定,再確認連接埠。
正確解讀輸出結果
詳細輸出表值得你仔細閱讀。標記為 f 的行程表示它將該 socket 作為檔案保持開啟狀態。標記為 c 的行程則表示它位於那個目錄中。對於網路檢查來說,你通常最關注的是 PID 和 COMMAND 這兩個欄位的組合。
簡寫形式能減少輸入量。執行 sudo fuser 80/tcp 會回傳一個純 PID 清單,適合腳本或快速查看。-v 參數則更適合人來閱讀。根據你是要立即處理,還是僅記錄結果,來選擇對應方式。
還有一個區別也很有幫助。某個運行在該連接埠上的行程,可能只是一個用戶端連線,而不一定是服務端監聽程式。詳細輸出會顯示命令名稱,因此你可以分辨它是瀏覽器還是常駐程式。這種上下文資訊能幫助你避免後續做出代價高昂的誤判。
終止占用連接埠的行程
使用 fuser 傳送訊號
有時你識別出某個行程後,會決定必須把它結束掉。fuser 命令可以直接替你傳送訊號。加上 -k 參數後,工具會終止所有附著在該 socket 上的行程。典型命令形如 fuser -k port/tcp,其中你需要把占位符替換成實際連接埠號。比如某個服務卡在連接埠 3000 上,你可以執行 fuser -k 3000/tcp。該工具預設傳送 SIGKILL,也就是立即強制結束行程,不給任何清理機會。對於生產環境中的服務來說,這種預設行為相當激烈。程式沒有機會刷新緩衝區,也無法正常關閉檔案。
你也可以選擇更溫和的訊號。-SIGNAL 選項允許你指定要傳送的訊號。例如,加上 -TERM 表示請求行程優雅退出。這樣程式就有機會關閉檔案並釋放資源。只有當優雅停止失敗時,再使用 SIGKILL。一個較好的順序是先發 TERM,稍等片刻,如果行程仍然存在,再發 KILL。把 -k 和 -v 結合起來還能讓你看到工具的執行過程。詳細模式會列印出每個收到訊號的 PID。操作之後請檢查退出狀態。回傳值為 0 表示訊號已成功送達目標。
-k 參數既可以與命名空間參數一起使用,也可以和 socket 參數一起使用。你可以寫成 fuser -k -n tcp 8080,也可以使用簡寫 fuser -k port/tcp。這兩種方式針對的是同一個行程。簡寫在終端機中處理繁忙連接埠時讀起來更快;長寫法則在腳本中更易於自我說明。選擇適合你工作流程的風格即可。
執行 kill 前的安全檢查
誤殺錯誤的行程可能會導致服務中斷、活動連線掉線,甚至打斷資料庫寫入。執行操作前,先確認兩件事:PID 和命令名稱。傳送訊號前請先執行詳細檢查。仔細查看 USER、PID 和 COMMAND 欄。問問自己:這個程式是否本來就應該在運行?一個 Web 伺服器占用某個繁忙 socket 是正常現象;而一個陌生二進位檔占著連接埠,則更值得調查,而不是立刻傳送 kill 訊號。如果命令名稱看起來不熟悉,請用 ps -p PID -o comm= 進行交叉驗證。操作前把 PID 記錄下來。如果後續服務出現故障,這份記錄會很有幫助。
永遠不要對一個尚未核實的 PID 執行 kill 命令。詳細輸出存在的意義,正是為了避免這種錯誤。
權限同樣很重要。你只能向自己擁有的行程傳送訊號。在共享 Linux 伺服器上,其他使用者的常駐程式會拒絕你的訊號。給命令加上 sudo 前綴,就能獲得所需權限。系統會提示你輸入密碼,然後再傳送該訊號。如果沒有這個前綴,工具會報錯,而且不會發生任何事情。
還有一個習慣也很有幫助:檢查該行程是否會自動重啟。很多服務都運行在某個 supervisor 的管理之下,幾秒鐘內就會被重新拉起。殺掉這樣的行程,只會短暫釋放連接埠,隨後同一個程式又會再次占用它。你需要先停止 supervisor,否則這個循環會不斷重複。不然你會一直追著同一個問題跑。kill 完成後,請再次執行詳細檢查,以確認連接埠已經釋放。
故障排除與交叉驗證
當 fuser 沒有回傳任何結果時
空結果並不總是意味著連接埠是空閒的。最常見的原因是協定不匹配。你檢查的是 TCP,但實際占用該 socket 的是一個 UDP 服務。在下結論之前,請使用另一種協定再查一次。
IPv6 是下一個常見「坑」。綁定在 IPv6 協定堆疊上的服務,可能不會出現在 IPv4 的查詢結果中,反之亦然。如果 「port already in use」 錯誤仍然存在,請測試兩種位址族。
權限問題則是最後一個常見原因。屬於其他使用者的行程,對你的帳號來說可能是不可見的。給命令加上 sudo,再重新查詢一遍。你可以用 fuser 快速檢查,但如果得到空結果,值得再多做一步確認。
使用 lsof 和 netstat 進行交叉檢查
驗證能避免誤判,另外兩個工具可以為你提供第二意見。OneUptime 部落格用一張簡潔的參考表記錄了這些常用命令:
工具 / 命令 | 用途 |
|---|---|
| 列出所有正在監聽的連接埠及其行程資訊(TCP 和 UDP) |
| 查找某個特定連接埠上的行程 |
| 顯示所有正在使用 80 連接埠的行程 |
| 按特定協定和連接埠進行查詢 |
當你需要更易讀的結果時,可以先從 lsof -i :3000 開始。它的輸出會在一行中給出命令名、使用者和 PID。加上 -t 參數後,則只回傳 PID 清單:lsof -t -i :3000 很適合腳本和 kill 命令。當 netstat 在非 root 帳號下無法顯示行程詳情時,OneUptime 建議使用 ss -tulpn | grep :3000 作為替代方案。
這些習慣在任何 Linux 伺服器上都很重要。要找出某個特定連接埠上正在監聽的行程/服務,請用第二個工具再確認一次。相同的原則也適用於你在繁忙主機上調查某個特定連接埠時。對某個連接埠做交叉驗證只需要幾秒鐘,卻可以幫助你發現協定或權限帶來的盲點。這才是在 Linux 中有把握地確認某個特定連接埠監聽情況的實用做法。
現在,你已經掌握了一套可重複使用的繁忙 socket 排查流程:
找出綁定失敗的連接埠。
執行
fuser -v -n tcp [port],取得 PID、使用者和命令名稱。決定是終止該行程,還是讓它繼續運行。
該工具在幾乎所有 Linux 系統中都隨 psmisc 套件一起提供,因此你可以在無需安裝額外軟體的情況下,使用 fuser 檢查連接埠。這使它非常適合用於快速的伺服器故障排除。
在終止行程之前務必先進行核實。查看命令名稱,確認所屬使用者,並檢查是否存在會自動重啟服務的 supervisor。一次謹慎的檢查,可以幫助你避免業務中斷。
常見問題
fuser 在所有 Linux 發行版上都能使用嗎?
大多數發行版都會將 fuser 包含在 psmisc 套件中,因此通常系統裡已經有了。如果命令執行失敗,可以先用 which fuser 檢查是否存在。某些極簡容器映像可能不會包含 psmisc,這時你可以安裝它,或者改用 lsof。
為什麼 fuser 只顯示 PID,卻不顯示命令名稱?
因為你沒有加詳細模式參數。預設輸出只會列出 PID。加上 -v 後,就能看到每個行程的使用者、存取類型和命令名稱。這些額外上下文有助於你在傳送訊號前確認程式身分。
我可以用同樣的命令檢查 UDP 連接埠嗎?
可以。只需替換協定參數:fuser -v -n udp [port]。TCP 查詢不會顯示 UDP 監聽器,因此參數必須與流量類型匹配。如果不確定,就把兩種都檢查一遍。
執行 fuser 一定需要 root 權限嗎?
不一定,但權限會影響你能看到的內容。你自己的行程無需提權也能看到。其他使用者的行程則只有在加上 sudo 後才會顯示。向某個特定行程持有者傳送訊號時,同樣遵循這一規則。
如果 fuser 和 lsof 的結果不一致怎麼辦?
不要盲信任何一個。先重新檢查協定和位址族,然後再用 ss -tulpn 做比較。陳舊條目或權限差異都可能導致結果不一致。在對 Linux 上的行程採取操作之前,請先使用 ps -p [PID] 再次確認 PID。
