我们有一个 Python 套接字线程服务器示例。这是一个稍加修改的版本 https://stackoverflow.com/a/23828265/2008247 。该示例有效,并且我的测试证实它的性能比阻塞服务器更好。
但在示例中,套接字和连接对象并未关闭。这两个对象都有 close()
方法。 (连接上的 close 方法仅在异常时调用。我希望在每个连接结束时调用它。)我们不需要以某种方式调用它们吗?如果是这样,怎么办?
#!/usr/bin/env python
import socket
import threading
class ThreadedServer():
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(5)
while True:
con, address = self.sock.accept()
con.settimeout(60)
threading.Thread(target=self.listenToClient,
args=(con, address)).start()
def listenToClient(self, con, address):
while True:
try:
data = con.recv(1024)
if data:
# Set the response to echo back the recieved data
response = data
con.send(response)
else:
raise Exception('Client disconnected')
except:
con.close()
return False
def main():
ThreadedServer('', 8001).listen()
if __name__ == "__main__":
main()
最佳答案
根据[Python.Docs]: socket.close() :
Sockets are automatically closed when they are garbage-collected, but it is recommended to close() them explicitly, or to use a with statement around them.
因此,所有套接字最终都会被关闭。但是,如果服务器运行很长时间并且(快速)创建/销毁大量连接,您可能最终会遇到文件描述符耗尽的情况,因此无法创建新的套接字,因此它是最好手动关闭它们。
有2个案例。
1。关闭服务器套接字
事情很简单。添加一个“析构函数”,或者更好的:终结器 ( [Python.Docs]: Data model - object.__del__(self) ) 到您的 ThreadedServer 类中:
def __del__(self):
#print("Closing server socket:", self.sock)
self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
这并不是真正必要的,因为服务器将在程序结束时被销毁,并且所有资源无论如何都会在此时被释放。
2。关闭每个客户端套接字
或者:
将 finally 子句 ( [Python.Docs]: Compound statements - The try statement ) 添加到 listenToClient 中的 try (此时,您还可以将该方法重命名为类似 listen_to_client):
# ... try: # Socket operation that might raise exceptions (con.recv) except: return False finally: #print("Closing connection:", con) con.shutdown(socket.SHUT_RDWR) con.close()
扩展Thread类,并在ThreadedServer.listen中使用它(这更优雅):
class ConnectionHandlingThread(threading.Thread): def __init__(self, target, connection, address): self.connection = connection super().__init__(target=target, args=(connection, address)) def run(self): super().run() #print("Closing connection:", self.connection) self.connection.shutdown(socket.SHUT_RDWR) self.connection.close()
及其用法:
ConnectionHandlingThread(listen_to_client, con, address).start()
替代方案
这一切看起来有点像重新发明轮子。这个具体场景的样板已存在于 socketserver 模块(Python 标准库的一部分)中。更多详情请查看[Python.Docs]: socketserver - Asynchronous Mixins .
关于Python 关闭线程服务器中的套接字和连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57841263/