多线程TCP套接字

时间:2018-05-31 19:58:43

标签: python multithreading sockets tcp socketserver

我正在尝试创建一个可以一次处理多个套接字请求的线程TCP套接字服务器。

为了测试它,我在客户端启动了几个线程,看看我的服务器是否可以处理它。第一个套接字已成功打印,但我得到[Errno 32] Broken pipe其他套接字。 我不知道如何避免它。

import threading
import socketserver
import graphitesend


class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        data = self.request.recv(1024)
        if data != "":
            print(data)

class ThreadedTCPServer(socketserver.ThreadingTCPServer):
    allow_reuse_address = True

    def __init__(self, host, port):
        socketserver.ThreadingTCPServer.__init__(self, (host, port), ThreadedTCPRequestHandler)

    def stop(self):
        self.server_close()
        self.shutdown()

    def start(self):
        threading.Thread(target=self._on_started).start()

    def _on_started(self):
        self.serve_forever()

def client(g):
    g.send("test", 1)

if __name__ == "__main__":
    HOST, PORT = "localhost", 2003
    server = ThreadedTCPServer(HOST, PORT)
    server.start()
    g = graphitesend.init(graphite_server = HOST, graphite_port = PORT)
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    threading.Thread(target = client, args=(g,)).start()
    server.stop()

1 个答案:

答案 0 :(得分:0)

确定您期望发生的事情有点困难,但我认为最近的原因是您在杀死服务器之前没有给客户提供时间。

构造Thread对象并调用其start方法时,您正在创建一个线程,并准备好运行它。然后它将被放置在系统上的“可运行”任务队列中,但它将与您的主线程和所有其他线程(以及同一台机器上的所有其他任务)竞争CPU时间。

您的多个线程(主要加上其他线程)也可能被python解释器的GIL(Global Interpreter Lock - 序列化 - 假设您正在使用“标准”CPython)这意味着他们甚至可能没有“出局”大门“还没有。

但是,在他们有机会发送任何内容之前,您将使用server_close()关闭服务器。这与“Broken Pipe”错误一致:您的其余客户端正在尝试写入已被“远程”端关闭的套接字。

您应该在创建线程对象时收集它们并将它们放在一个列表中(以便以后可以引用它们)。当您完成创建并启动所有这些时,然后返回列表并在每个线程对象上调用.join方法。这将确保线程有机会完成。只有这样才能关闭服务器。像这样:

threads = []
for n in range(7):
    th = threading.Thread(target=client, args=(g,))
    th.start()
    threads.append(th)

# All threads created. Wait for them to finish.
for th in threads:
    th.join()

server.stop()

另外需要注意的是,所有客户端都共享同一个连接以发送到服务器,因此您的服务器永远不会创建多个线程:就其而言,只有一个客户端。如果您确实希望为每个客户端分别建立连接,则应该将graphitesend.init移动到客户端函数中。

(免责声明:我对graphitesend一无所知,除了我可以在15秒内查看谷歌的第一个结果;我假设它基本上只是TCP连接的包装。)