簡體   English   中英

連接超過SocketServer.TCPServer嗎?

[英]Connections outlive SocketServer.TCPServer?

如何使TCP服務器正確關閉套接字?

我編寫了一個簡單的TCP服務器,將某些信息回顯給客戶端。 現在,我想在localhost:8088上使用它,並使用killall停止它,並在我處理代碼時隨時重新啟動。

但是,我無法使其關閉所有套接字並“釋放”地址,因此,當我快速進行一些測試時,修復代碼中的某些內容,然后停止(Ctrl + C)並再次啟動服務器,我得到了socket.error: [Errno 98] Address already in use

當我sudo netstat -ntap ,我仍然可以看到幾個127.0.0.1:8088套接字處於TIME_WAIT狀態。 所以我必須等到他們“消亡”。

我的測試用例:

#!/usr/bin/python
import SocketServer

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\nhello."
        self.request.send(self.reply)
        self.request.close()

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler)
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

我究竟做錯了什么? self.request.close()是否足夠?

我正在使用Python 2.7.3在Debian上進行嘗試,盡管我也需要在Python 2.6中支持Squeeze。

TCP堆棧將端口置於定時等待一段時間(大約30秒到幾分鍾,具體取決於您的系統)。 您可以使用SO_REUSEADDR套接字選項更改該行為。 訣竅是必須在綁定端口之前設置該選項。

如果您有原始套接字,則可以:

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

SocketServer允許您使用allow_reuse_address屬性全局設置選項:

SocketServer.TCPServer.allow_reuse_address = True

或者,您可以在創建服務器時執行以下操作:

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler, False)
    server.allow_reuse_address = True
    server.server_bind()
    server.serve_forever()

甚至重寫bind方法:

class MyTCPServer(SocketServer.TCPServer):

    def server_bind(self):
        self.allow_reuse_address = True
        super(MyTCPServer, self).server_bind()

以下是在Windows計算機上對我有用的3種解決方案。

(1)全局設置

#!/usr/bin/python
import SocketServer
import time

SocketServer.allow_reuse_address = True

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\n" + time.asctime()
        self.request.send(self.reply)
        self.request.close()

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler)
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

(2)本地設置

#!/usr/bin/python
import SocketServer
import time

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\n" + time.asctime()
        self.request.send(self.reply)
        self.request.close()

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler, False)
    server.allow_reuse_address = True
    server.server_bind()
    server.server_activate()
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

(3)繼承

#!/usr/bin/python
import SocketServer
import time

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\n" + time.asctime()
        self.request.send(self.reply)
        self.request.close()

class MyTCPServer(SocketServer.TCPServer):

    def server_bind(self):
        self.allow_reuse_address = True
        SocketServer.TCPServer.server_bind(self)

def main():
    server = MyTCPServer((HOST, PORT), MyEchoHandler)
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

您可以調用server.shutdown(),但必須從另一個線程8-(IMO,這是Python的TCPServer中的弱點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM