使用新版本 Tornado 开发 WebSocket 程序的问题

使用新版本 Tornado 开发 Websocket 程序的问题

  最近,在用 tornado 开发 Websocket 程序时,新装了开发环境。发现原来能够运行的程序突然出错了。tornado.websocket.WebSocketHandler 的派生类运行时,一旦有客户端连接,就报出如下错误,并拒绝连接:

TypeError: WebSocketSubscription.__init__() takes 1 positional argument but 3 were given

  新装环境使用的 Tornado 版本是 6.3.2。查找官方文档(https://www.osgeo.cn/tornado/websocket.html?highlight=websocket#module-tornado.websocket),使用其提供的如下样例程序进行测试是没有问题的。

class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

  和我们的原有程序相比,这个程序没有派生类的初始化函数。如果在这个程序上加上初始化函数,并按原有方式调用父类初始化函数,则同样会产生上述问题。

class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def __init__(self):
        super().__init__()

    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

  官方文档中,给出了初始化时应当给出的3个调用参数:
  1. application: tornado.web.Application、
  2. request: tornado.httputil.HTTPServerRequest、
  3. **kwargs: Any
  但文档中并未给出派生类调用初始化__init__() 函数的样例,使用以前版本时,也从未遇到这个问题。由于实际运行时,WebSocketHandler 的是在连接生成实例时自动调用初始化的,所以也不可能在连接时给出明确的参数。如果不调用父类的初始化,派生类的各种初始化操作就无法执行,所以必须解决这个问题。(当然,也可以将 WebSokcetHandler 对象作为成员加入原来的派生类,但这涉及到程序比较大的修改。)
  在参数数量和类型不明确的情况下,Python 程序常用 *args**kwargs 的方式来传递参数,试了一下,在这种情况下是奏效的,简单加了两个参数后,程序就能够正常运行。修改后的样例程序如下:

class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def __init__(self, *args, **kwargs):
        super().__init__( *args, **kwargs)

    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

  和我们以前使用的版本相比,新版本还有一些值得注意特性,例如:
  1. 增加了check_origin 函数检测跨源,以前是不阻止非同源接入的;
  2. 可以以更简洁方式启动 WebSocketHandler 对象。
  检查跨源程序的例子(无条件允许跨源):

def check_origin(self, origin):
    return True

  启动对象的例子:

def make_app():
    return tornado.web.Application([
        (r"/websocket", EchoWebSocket),
    ])


async def main():
    app = make_app()
    app.listen(8000)
    await asyncio.Event().wait()

if __name__ == "__main__":
    asyncio.run(main())

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值