某支服務程式監聽9000、12000、12001三個TCP Port提供服務,要啟動時出現該Port已被佔用的錯誤訊息。

這是很常見的情境,既然Port被現有程式佔用,最簡單的做法就是netstat –oa找出LISTEN該Port程式的Process ID,結束該程序即可。但這回情況遠比想像複雜...

netstat查出這三個Port被一支PID=5300的程序所佔用(應是先前當掉的同一服務程式),但由Task Manager或Process Explorer卻找不到PID=5300的程序,既然找不到程序就無從砍起,不把程序砍掉,Port就會一直被佔用著,重開機或重啟網卡是最簡便的解決手段,卻限於主機上仍有其他服務不能中斷而不可行。

束手無策之際,改用TCP View檢查發現異常之處: PID=5300程序,除了聽9000, 12000, 12001三個Port外,還有一些殘留的連線(狀態為CLOSE_WAIT),而其Process Name標示為<non-existent>,代表該Porcess已經不存在,雖然按右鍵選單可以選擇終結程序,但試著關閉不存在的程序,想當然於事無補。就這樣再度陷入焦著,狀況很明確 -- 只要關掉不存在的程序就能解決問題,問題是關不掉。

爬文爬了很久,一堆文章建議用pskill、Process Explorer刪掉程序即可,我想他們肯定沒見過這枚看得到打不到的BOSS級茶包。終於,在serverfault找到一篇很棒的討論回應為我解惑:

What may be happening is that your process had a TCP port open when it crashed or otherwise exited without explicitly closing it. Normally the OS cleans up these sorts of things, but only when the process record goes away. While the process may not appear to be running any more, there is at least one thing that can keep a record of it around, in order to prevent reuse of its PID. This is the existence of a child process that is not detached from the parent.

文中提到一個重點,當Process開啟TCP Port後未正常結束就當掉,理論上OS會幫忙善後歸還其佔用資源,前題是 -- Process的PID記錄已自OS中移除。若該程序啟動了子程序(Child-Process),程序終止後子程序繼續存活,子程序的Parent PID仍指向該程序,對OS來說,該PID仍有意義,其佔用的TCP Port便不能任意處置。這充分解釋我遇到的狀況,很明顯的,找出並終結已成為孤兒(Orphaned)的子程序,讓PID 5300徹底安息,這一切就能解套。

使用Process Explorer開始對Process進行盤查,很快發現有一個dw20.exe(Dr.Watson,當機善後程式)行跡可疑,點開一看,BINGO!!! Parent就指向5300,推論是5300 Process當機後啟動,卻不知為何一直沒有自行結束才惹出事端。

將Dr.Watson就地正法(Kill Process),原本PID 5300佔用的所有TCP Port瞬間被釋放,Case Closed!


Comments

# by shiyiwan

谢谢分享

Post a comment