使用Python的线程TCP套接字
我刚开始学习Python编程和socket,所以我从一个异步(多线程)SocketServer的例子入手,具体可以参考这个链接。
这个ThreadingMixIn类的例子运行得不错,不过我有两个问题想请教专家:
每当有新连接时,都会创建一个新线程,这很好。但我发现这些线程似乎从来不会结束,即使另一端的连接已经关闭,线程的数量还是在不断增加。
第二个问题是关于handle方法的。我尝试从客户端发送两个连续的消息,使用sendall,但第二次发送失败了……看起来handle方法实际上是在等待第一条消息,然后就结束了。我不得不加一个'while 1:'才能让它正常工作。
所以总结一下,我觉得这个例子没什么用,感觉很糟糕,因为它只创建了一个只能接收一条消息的线程。如果至少它能自己结束就好了,但对我来说似乎并不是这样……
谢谢大家的建议!
这是服务器的代码:
import threading
import SocketServer
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
cur_thread = threading.current_thread()
response = "{}: {}".format(cur_thread.name, data)
self.request.sendall(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if __name__ == "__main__":
server = ThreadedTCPServer(('localhost', 13009), ThreadedTCPRequestHandler)
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
raw_input("Hit enter to stop the server")
server.shutdown()
这是客户端的代码:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 13009))
try:
sock.sendall('hello\n')
response = sock.recv(1024)
print "Received: {}".format(response)
# A second 'send' will generate an error on Windows.
# On Mac, no error but the received message is empty as the
# handle method in the server isn't called for each new message
sock.sendall('how are you?')
response = sock.recv(1024)
print "Received: {}".format(response)
except socket.error, (value,message):
print "Error: " + message
finally:
sock.close()
正如你所看到的,每次运行客户端的代码时,都会创建一个新线程,即使之前的socket已经关闭……或者说,threading.current_thread()返回了一个新的ID。我该如何检查之前的线程是否已经停止?
2 个回答
- Python是单线程运行的,所以如果你想通过使用多个线程来提高性能,其实是没什么效果的。这样做可能还会浪费更多的内存。
- 我建议使用gevent这个库,它可以帮助你更简单地处理并行执行和管理大量的网络连接。
关于@luka的回答,Dietrich说得对,这种使用线程的方式是没问题的。没错,Python在任何时候只能执行一条指令,但通常来说,网络连接(套接字)主要是受输入输出限制的,所以这样做是可以的。
想要知道一个线程是否已经结束,最简单的方法不是直接通过Python来判断,因为这在你使用的接口中有些抽象。相反,我建议查看操作系统,它可以提供这些信息。在Linux系统中,只需执行pstree
命令。你的线程数量会显示为类似<thread count>*[{process name}]
的格式,其中线程数量就是你的线程个数。
其他方法包括让你的应用程序打印“开始线程”,然后打印“结束线程”,或者使用Python调试器(pydb)。
关于@luka提到的事件驱动Python,实际上这有点过早优化。如果你不预期你的应用会承受很大的负载,那就不用担心。如果你预计会有很大的负载,那么每个请求都创建一个线程可能会成为一个瓶颈,需要解决。