V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
GYGYG
V2EX  ›  Python

tornado 框架大佬求入

  •  
  •   GYGYG · 2022-05-12 18:07:08 +08:00 · 2544 次点击
    这是一个创建于 927 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求是用 tornado 实现一个 websocket 接口,来实现 socket 消息的透传。 由于 sock.recv 是阻塞的,协程实现的话,总是会卡在第二次循环并且超时。 大致的代码如下:

    
    import socket
    
    import tornado.websocket
    from tornado import gen
    
    
    class WebSocketHandler(tornado.websocket.WebSocketHandler):
        sock = socket
    
        @gen.coroutine
        def _read_from_sock(self, sock: socket, buffer_size: int):
            while True:
                try:
                    chunk = sock.recv(buffer_size)
                    if not chunk:
                        return
                    self.write_message(chunk)
                except socket.timeout:
                    raise tornado.websocket.WebSocketError('timeout!')
    
        def open(self, container_id):
            self._read_from_sock(self.sock, 4096)
    
        def on_message(self, message):
            self.sock.sendall(message.encode(encoding='utf-8'))
    
        def on_close(self):
            pass
    
    

    我想在主线程中实现 socket 的监听并返回 write_message ,但是这样的协程似乎不可以,子线程试过也是会阻塞。不知道问题出在哪里?求大佬帮帮忙。谢谢了!

    9 条回复    2022-05-20 09:58:07 +08:00
    neoblackcap
        1
    neoblackcap  
       2022-05-12 18:20:56 +08:00
    问题就是你把 socket 跟 tornado 混在一起了,tornado 已经帮你处理了底层 socket 的逻辑,包括 IO 复用。
    你需要做的是在 on_message 里面写你的逻辑,并放弃使用标准库里面的 socket ,从而使用 WebSocketHandler.write_message 等方法
    fgwmlhdkkkw
        2
    fgwmlhdkkkw  
       2022-05-12 18:23:01 +08:00
    sock.setblocking(False);
    GYGYG
        3
    GYGYG  
    OP
       2022-05-12 18:23:44 +08:00
    @neoblackcap 这里的 socket 是 open 时 需要与另外的服务端完成的 socket 链接。也就是我要实现一个 WebSocketHandler ,内部逻辑是与中转与另一个 websocket 客户端的通信。
    fgwmlhdkkkw
        4
    fgwmlhdkkkw  
       2022-05-12 18:24:13 +08:00
    @fgwmlhdkkkw #2 我不了解 tornado ,1 楼应该没问题。
    neoblackcap
        5
    neoblackcap  
       2022-05-12 18:47:26 +08:00
    @GYGYG 最简单的方法就是,你使用 tornado 自带的 tornado.tcpclient.TCPClient
    当然你像二楼说的,你自己创建一个连接也是完全可以的,前提是你要把该连接设置成非堵塞,并把它注册到 tornado 的 IOLoop 上。
    zhuangzhuang1988
        6
    zhuangzhuang1988  
       2022-05-12 21:40:11 +08:00
    用 IOStream.
    Kobayashi
        7
    Kobayashi  
       2022-05-13 21:55:29 +08:00
    > 来实现 socket 消息的透传

    你要实现一层 websocket 代理,直接在 Nginx 上做不好吗?

    鉴于示例代码中你对 tornado 的理解,不建议在代码层用 Python 来做这个事情。利用 tornado 做 websocket 代理,不仅需要理解异步中利用轮询处理 socket 的方式,还要完全掌握 websocket 协议。即便我翻过 tornado 源码我也不会选择用这个方式解决问题。
    lolizeppelin
        8
    lolizeppelin  
       2022-05-15 12:46:39 +08:00
    socket 代理用 websockify 这个库就好
    openstack 就用这个来转发 vnc

    别自己吃力不讨好的折腾其他的
    GYGYG
        9
    GYGYG  
    OP
       2022-05-20 09:58:07 +08:00
    @Kobayashi 暂时用线程实现了。。。想去看教程理解 tornado 有点难。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2894 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:12 · PVG 20:12 · LAX 04:12 · JFK 07:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.