python -- socket關閉后地址占用問題

class MyHttpHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        print "do get"
        self.send_response(code=200)
        self.end_headers()
        self.wfile.write("hello world")

if __name__ == '__main__':
    serv = TCPServer(('', 20001), MyHttpHandler)
    serv.serve_forever()

上面這段代碼,運行,client訪問多次后關閉,再啟動,會報一個socket.error: [Errno 48] Address already in use的錯。lsof -i:20001 沒能找到任何進程占用端口,一個乍一看很迷的錯誤,記錄下,怕以后忘掉。

解決方案很簡單,增加TCPServer.allow_reuse_address = True。具體起作用的為socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)這。

原因如下。操作系統的網絡棧會非常謹慎的處理連接的關閉,僅僅用于監(jiān)聽的服務器套接字是可以立即關閉并操作系統忽略的,但是對于實際與客戶端進行通信的連接套接字就不行了。即使客戶端和服務器都關閉了連接并向對方發(fā)從了FIN數據包,連接套接字也無法立即取消。為什么呢?因為即使網絡棧發(fā)送了最后一個數據包將套接字關閉,也還是無法確認該數據包是否可以被接收。如果數據包正好被網絡丟棄了,那么另一方無法得知該數據包長時間無法傳達的原因,可能會重新發(fā)送FIN數據包,希望能收到響應。

操作系統對上述問題的解決方案為,一個應用程序任務某個TCP連接最終關閉了,操作系統的網絡棧實際上會在一個等待狀態(tài)中將該連接的記錄保存最多4分鐘。RFC將這些狀態(tài)命名為CLOSE-WAIT 和TIME-WAIT,當關閉的套接字還處于其中某一狀態(tài)時,任何最終的FIN數據包都是可以得到適當響應的。

因此,當服務器試圖聲明某個幾分鐘前運行的連接所使用的端口時,實際上是在試圖聲明從某種意義上仍在使用的端口。所以就報錯了~

而SO_REUSEADDR可以指明應用程序能夠使用一些網絡客戶端之前的連接正在關閉的端口。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)、netstat -nat 查看TCP各個狀態(tài)的數量2)、lso...
    北辰青閱讀 9,728評論 0 11
  • 一: 網絡各個協議:TCP/IP、SOCKET、HTTP 網絡七層由下往上分別為物理層、數據鏈路層、網絡層、傳輸層...
    iYeso閱讀 1,511評論 0 13
  • 一、網絡各個協議:TCP/IP、SOCKET、HTTP等 網絡七層由下往上分別為物理層、數據鏈路層、網絡層、傳輸層...
    杯水救車薪閱讀 2,362評論 0 17
  • 感知型攝像機也叫Intelligent IPC,是2014年推出的一種新型智能攝像機,不同于傳統的智能攝像機,它由...
    Kedacom1995閱讀 1,026評論 0 1
  • 聽歌的青年 聽歌的青年, 手指打著節(jié)拍, 律動,舞蹈,夢馬。 微風過處彈鋼琴, 撫天長,姑娘的俏臉, 張手作翅, ...
    南溪向南北歌流海閱讀 208評論 0 0

友情鏈接更多精彩內容