Python:在两个端口上监听

5 投票
2 回答
15433 浏览
提问于 2025-04-16 03:47
import socket
backlog = 1 #Number of queues

sk_1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk_2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

local = {"port":1433}
internet = {"port":9999}

sk_1.bind (('', internet["port"]))
sk_1.listen(backlog)

sk_2.bind (('', local["port"]))
sk_2.listen(backlog)

基本上,我有这段代码。我想在两个端口上监听:1433 和 9999。但是,这似乎不太管用。

我该怎么在同一个 Python 脚本中监听这两个端口呢?

2 个回答

4

到目前为止,代码是没问题的,虽然设置一个连接请求的数量为1有点严格。真正的问题出现在你尝试在任何一个监听的套接字上使用accept时,因为accept通常是一个阻塞调用。这意味着它会一直等待,直到有连接进来。而如果你试图交替在两个套接字上用短时间的超时来“轮询”连接,这样会浪费计算机的资源,没什么好处。

这时候就需要用到select了!select.select(或者在更好的操作系统上用select.poll,甚至select.epollselect.kqueue……不过,老牌的select.select在任何地方都能用!)可以告诉你哪个套接字准备好了,什么时候准备好,这样你就可以适时地使用accept。此外,asyncoreasynchat提供了更好的组织结构(当然,第三方框架twisted也增加了很多这样的“异步”功能)。

另外,你也可以为两个监听套接字各开一个独立的线程来处理,但如果这两个套接字需要共享一些数据结构,就可能会出现协调的问题(比如锁的问题等)。我建议你先尝试异步的方法——其实这样更简单,而且有可能大幅提升性能!

11

如果你想用Python自带的库来做这个事情,比较高级的做法是使用SocketServer配合ThreadingMixin。不过,使用'选择'(select)的方法可能会更高效一些。

虽然我们只定义了一个ThreadedTCPRequestHandler,但你可以很容易地调整它,让每个监听器都有自己独特的处理器。如果你喜欢这样做,把服务器和线程的创建放到一个方法里也是很简单的。

#!/usr/bin/python

import threading
import time
import SocketServer

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        print "%s wrote: " % self.client_address[0]
        print self.data
        self.request.send(self.data.upper())

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

if __name__ == "__main__":

    HOST = ''
    PORT_A = 9999
    PORT_B = 9876

    server_A = ThreadedTCPServer((HOST, PORT_A), ThreadedTCPRequestHandler)
    server_B = ThreadedTCPServer((HOST, PORT_B), ThreadedTCPRequestHandler)

    server_A_thread = threading.Thread(target=server_A.serve_forever)
    server_B_thread = threading.Thread(target=server_B.serve_forever)

    server_A_thread.setDaemon(True)
    server_B_thread.setDaemon(True)

    server_A_thread.start()
    server_B_thread.start()

    while 1:
        time.sleep(1)

撰写回答