Python:在两个端口上监听
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.epoll
或select.kqueue
……不过,老牌的select.select
在任何地方都能用!)可以告诉你哪个套接字准备好了,什么时候准备好,这样你就可以适时地使用accept
。此外,asyncore
和asynchat
提供了更好的组织结构(当然,第三方框架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)