【问题标题】:Callbacks from autobahn WebSocketClientProtocol to another object从高速公路 WebSocketClientProtocol 回调到另一个对象
【发布时间】:2016-01-08 11:56:03
【问题描述】:

首先,有一个IO 类,它在__init__ 上传递了之前在主类中创建的异步循环对象(io = IO(loop))。 IO 类然后在某些时候通过执行self.socket = Socket(self) 来初始化Socket 类,以便套接字对象具有向后访问权限。后来Socket类初始化Websocket类,它是Transport的子类

class Websocket(Transport):

    name = 'websocket'

    def __init__(self, socket):
        self.socket = socket

    def open(self):
        url = self.prepareUrl()

        factory = WebSocketClientFactory(url, debug = False)
        factory.protocol = Protocol

        websocket = self.socket.loop.create_connection(factory, host=self.socket.io.options.host, port=self.socket.options.port)

        self.socket.io.loop.run_until_complete(websocket)

    def onOpen(self):
        print('print me please!')

因此,socket 对象调用self.transport.open()(其中self.transport = Websocket(self)),它创建高速公路工厂,通过执行self.socket.loop.create_connection() 创建异步连接,然后通过执行run_until_complete() 将coro future 添加到循环中。

现在,问题就从这里开始: 高速公路工厂需要一个类,该类必须继承自autobahn.asyncio.websocket.WebSocketClientProtocol

我的班级Protocol(WebSocketClientProtocol) 有平常的:

class Protocol(WebSocketClientProtocol):

    @asyncio.coroutine
    def onOpen(self):
        print('socket opened!')

这工作得很好,print('socket opened!') 确实打印了字符串,我的服务器也说连接是打开的。

问题: 从 Protocol() 类中,当高速公路调用 onOpen() 回调时,如何使此方法调用 transport.onOpen() 方法并执行print('print me please!')

【问题讨论】:

  • 目前我发现的唯一解决方案是在循环对象中引用套​​接字对象,这样我就可以从Protocol.onOpen() 协程中执行类似self.factory.loop.socket.transport.onOpen() 的操作。为了使事情更漂亮,我可以将循环对象作为基线传递,它的结构类似于loop.io.socket.transport。但同样,循环对象是否真的打算在其内部保存第三方引用?对我来说,这看起来有点太 hacky...
  • 在 cpp 中,我将信号 2 用于类似目的,出于某种原因,这次我试图为 python 搜索术语“信号”......当然还没有找到任何相关的东西...... . 现在,我正在研究 PyDispatcher 和其他人。如果在我找到足够好的解决方案之前没有人发帖,我会自行回答 q。我想我现在走在正确的轨道上。

标签: python python-3.x python-asyncio autobahn


【解决方案1】:

好的,所以我修好了!使用 PyDispatch 模块轻松完成。

这是我的解决方案:

import asyncio
from pydispatch import dispatcher
from autobahn.asyncio.websocket import WebSocketClientProtocol, WebSocketClientFactory

from ..transport import Transport

class Websocket(Transport):

    name = 'websocket'

    def __init__(self, socket):
        self.socket = socket

    def open(self):
        url = self.prepareUrl()

        factory = WebSocketClientFactory(url, debug = False)
        factory.protocol = Protocol

        websocket = self.socket.loop.create_connection(factory, host=self.socket.io.options.host, port=self.socket.options.port)

        dispatcher.connect(self.onOpen, signal='open', sender=dispatcher.Anonymous)

        self.socket.io.loop.run_until_complete(websocket)

    def onOpen(self):
        print('print me please!')


class Protocol(WebSocketClientProtocol):

    @asyncio.coroutine
    def onOpen(self):
        dispatcher.send(signal='open')

更新

我有另一个 IMO 更好的解决方案。这个没有使用 PyDispatch。由于异步任务完成时有一个回调,它返回用户定义的协议对象(继承自 WebSocketClientProtocol),我们可以使用它来将两个对象链接在一起:

import asyncio
from autobahn.asyncio.websocket import WebSocketClientProtocol, WebSocketClientFactory

from ..transport import Transport

class Protocol(WebSocketClientProtocol):

    def __init__(self):
        self.ws = None
        super().__init__()

    @asyncio.coroutine
    def onConnect(self, response):
        pass # connect handeled when SocketIO 'connect' packet is received

    @asyncio.coroutine
    def onOpen(self):
        self.ws.onOpen()

    @asyncio.coroutine
    def onMessage(self, payload, isBinary):
        self.ws.onMessage(payload=payload, isBinary=isBinary)

    @asyncio.coroutine
    def onClose(self, wasClean, code, reason):
        if not wasClean:
            self.ws.onError(code=code, reason=reason)

        self.ws.onClose()           

class Websocket(Transport):

    name = 'websocket'

    def __init__(self, socket, **kwargs):
        super().__init__(socket)

        loop = kwargs.pop('loop', None)
        self.loop = loop or asyncio.get_event_loop()

        self.transport = None
        self.protocol = None

        self.ready = True

    def open(self):
        url = self.prepareUrl()
        if bool(self.socket.options.query):
            url = '{0}?{1}'.format(url, self.socket.options.query)

        factory = WebSocketClientFactory(url=url, headers=self.socket.options.headers)
        factory.protocol = Protocol

        coro = self.loop.create_connection(factory, host=self.socket.options.host, port=self.socket.options.port, ssl=self.socket.options.secure)

        task = self.loop.create_task(coro)
        task.add_done_callback(self.onWebSocketInit)

    def onWebSocketInit(self, future):
        try:
            self.transport, self.protocol = future.result()
            self.protocol.ws = self
        except Exception:
            self.onClose()

    def send(self, data):
        self.protocol.sendMessage(payload=data.encode('utf-8'), isBinary=False)
        return self

    def close(self):
        if self.isOpen:
            self.protocol.sendClose()
        return self

    def onOpen(self):
        super().onOpen()
        self.socket.setBuffer(False)

    def onMessage(self, payload, isBinary):
        if not isBinary:
            self.onData(payload.decode('utf-8'))
        else:
            self.onError('Message arrived in binary')

    def onClose(self):
        super().onClose()
        self.socket.setBuffer(True)

    def onError(self, code, reason):
        self.socket.onError(reason)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    相关资源
    最近更新 更多