1、问题背景
项目中我们需要通过 Tornado HTTP 处理程序建立WebSocket连接,该连接需要处理多个用户请求,并且将从外部服务器获取的数据存储到数据库中。我们尝试了以下实现:
python
from twisted.internet import reactor
from autobahn.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS
from tornado.options import define, options, parse_command_line
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
self.write("This is your response")
factory = WebSocketClientFactory("ws://localhost:7096")
factory.protocol = BridgeSocket
connectWS(factory)
self.finish()
reactor.run()
class BridgeSocket(WebSocketClientProtocol):
def sendHello(self):
self.sendMessage("rails")
def onOpen(self):
self.sendHello()
def onMessage(self, msg, binary):
print "Got echo: " + msg
def onClose(wasClean,code,reason):
print "GETTING CLOSE CONNECTION"
print str(wasClean)+" ---"+str(code)+"---"+str(reason)
reactor.stop()
但是,reactor.run()会阻止对Tornado Web服务器的进一步HTTP请求,如果我们在WebSocket工作完成后立即调用reactor.stop(),又会发现无法重新启动reactor。
2、解决方案
为了在Tornado中运行AutobahnPython的WebSocket客户端,我们需要使用Twisted-Tornado集成("Twisted on Tornado")。这个库允许我们在Tornado中运行Twisted reactor循环。
以下是如何使用Twisted on Tornado来解决问题的步骤:
-
安装Twisted on Tornado:
pip install twisted-tornado
-
在你的Tornado应用程序中导入Twisted on Tornado:
javascript
from twisted.internet import reactor
from twisted.internet.defer import Deferred
from tornado.ioloop import IOLoop
- 在你的Tornado HTTP处理程序中,使用Twisted on Tornado的reactor来运行WebSocket客户端:
css
def main():
reactor.suggestThreadPoolSize(1) # Increase threadpool size for multiple persistent connections
IOLoop.instance().run(True)
reactor.callWhenRunning(main)
- 修改你的WebSocket客户端协议类,使其继承自Twisted的WebSocketClientFactory:
ruby
class BridgeSocket(WebSocketClientFactory):
def buildProtocol(self, addr):
return BridgeSocketProtocol()
class BridgeSocketProtocol(WebSocketClientProtocol):
def sendHello(self):
self.sendMessage("rails")
def onOpen(self):
self.sendHello()
def onMessage(self, msg, binary):
print "Got echo: " + msg
def onClose(self, wasClean, code, reason):
print "GETTING CLOSE CONNECTION"
print str(wasClean)+" ---"+str(code)+"---"+str(reason)
reactor.stop()
- 在你的Tornado应用程序中,使用Twisted on Tornado的reactor来连接到WebSocket服务器:
scss
from twisted.internet import reactor
def connect_to_websocket():
factory = BridgeSocket()
reactor.connectTCP("localhost", 7096, factory)
reactor.callWhenRunning(connect_to_websocket)
这样,我们就可以在Tornado中使用AutobahnPython的WebSocket客户端,而不会阻止对Tornado Web服务器的进一步HTTP请求。