python TCP服務(wù)器端口占用難題及解決方案
在使用Python編寫TCP服務(wù)器時,程序退出后目標(biāo)端口仍然被占用的情況時有發(fā)生,導(dǎo)致服務(wù)器無法立即重啟。本文將分析此問題,并提供有效的解決方法。
問題:使用multiprocessing.pool創(chuàng)建進(jìn)程池的TCP服務(wù)器,異常終止后,lsof -i :6001未顯示端口6001被占用,但重啟服務(wù)器時報錯OSError: [errno 98] Address already in use。netstat -anp | grep 6001顯示大量TIME_WaiT狀態(tài)連接。
原因分析:lsof顯示的是進(jìn)程正在使用的文件描述符,而TIME_WAIT狀態(tài)的連接并非由任何進(jìn)程直接持有。TCP連接關(guān)閉后,操作系統(tǒng)會將其保持在TIME_WAIT狀態(tài)一段時間(通常60-120秒),以確保數(shù)據(jù)包可靠傳輸。在此期間,端口處于“占用”狀態(tài),但并非被進(jìn)程使用,lsof無法檢測到。netstat命令則清晰地顯示了大量的TIME_WAIT連接,這正是問題根源。服務(wù)器意外退出導(dǎo)致客戶端連接未正常關(guān)閉,從而阻塞端口。
解決方案:在服務(wù)器綁定端口前,設(shè)置套接字選項SO_REUSEADDR。這允許同一程序的多個套接字綁定同一端口。修改代碼如下:
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 在bind之前添加 serversocket.bind(('0.0.0.0', port))
通過設(shè)置SO_REUSEADDR,可以有效避免TIME_WAIT狀態(tài)導(dǎo)致的端口占用問題,從而實現(xiàn)服務(wù)器快速重啟。 linux 3.9及以上內(nèi)核版本還提供SO_REUSEPORT選項,可實現(xiàn)更精細(xì)的端口復(fù)用,某些情況下可與SO_REUSEADDR結(jié)合使用。windows系統(tǒng)可能需要額外設(shè)置SO_EXCLUSIVEADDRUSE選項。