【问题标题】:How create a python application with two thread each which has a autobahn application如何创建一个带有两个线程的 python 应用程序,每个线程都有一个高速公路应用程序
【发布时间】:2015-04-09 11:02:28
【问题描述】:

我还没有为我的问题找到任何解决方案。我需要创建一个带有两个线程的 python 应用程序,每个线程都使用高速公路库连接到一个 WAMP 路由器。

跟着我写我的实验代码:

wampAddress = 'ws://172.17.3.139:8181/ws'
wampRealm = 's4t'

from threading import Thread
from autobahn.twisted.wamp import ApplicationRunner
from autobahn.twisted.wamp import ApplicationSession
from twisted.internet.defer import inlineCallbacks


class AutobahnMRS(ApplicationSession):
    @inlineCallbacks
    def onJoin(self, details):
        print("Sessio attached [Connect to WAMP Router]")

        def onMessage(*args):
            print args
        try:
            yield self.subscribe(onMessage, 'test')
            print ("Subscribed to topic: test")

        except Exception as e:
            print("Exception:" +e)

class AutobahnIM(ApplicationSession):
    @inlineCallbacks
    def onJoin(self, details):
        print("Sessio attached [Connect to WAMP Router]")

        try:
            yield self.publish('test','YOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO')
            print ("Subscribed to topic: test")

        except Exception as e:
            print("Exception:" +e)

class ManageRemoteSystem:
    def __init__(self):
        self.runner = ApplicationRunner(url= wampAddress, realm = wampRealm)

    def start(self):
        self.runner.run(AutobahnMRS);


class InternalMessages:
    def __init__(self):
        self.runner = ApplicationRunner(url= wampAddress, realm = wampRealm)

    def start(self):
        self.runner.run(AutobahnIM);

#class S4tServer:

if __name__ == '__main__':
    server = ManageRemoteSystem()
    sendMessage = InternalMessages()

    thread1 = Thread(target = server.start())
    thread1.start()
    thread1.join()

    thread2 = Thread(target = sendMessage.start())
    thread2.start()
    thread2.join()

当我启动这个 python 应用程序时,只启动了 thread1,然后当我终止应用程序 (ctrl-c) 时,会显示以下错误消息:

Sessio attached [Connect to WAMP Router]
Subscribed to topic: test
^CTraceback (most recent call last):
  File "test_pub.py", line 71, in <module>
    p2 = multiprocessing.Process(target = server.start())
  File "test_pub.py", line 50, in start
    self.runner.run(AutobahnMRS);
  File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/wamp.py", line 175, in run
    reactor.run()
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1191, in run
    self.startRunning(installSignalHandlers=installSignalHandlers)
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1171, in startRunning
    ReactorBase.startRunning(self)
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 683, in startRunning
    raise error.ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable

我需要在一个具有其功能的应用程序中实现,并且它还必须有一个系统来与带有高速公路 python 库的 WAMP 路由器通信。

换句话说,我需要一个能够与 WAMP 路由器通信的解决方案,但同时这个应用程序不必被高速公路部分阻塞(我认为解决方案是启动两个线程,一个线程管理一些功能,第二个线程管理高速公路部分)。

对于我之前提出的模式,还有另一个问题,需要在 WAMP 路由器上的特定主题中发送消息,从“无高速公路线程”中的应用程序部分,这个功能应该通过调用一个特定的功能,而不阻塞其他功能。

我希望我已经提供了所有细节。

非常感谢您的任何回复

--------------------------------编辑-------------- -------------------

经过一番研究,我已经实现了我需要的 websocket 协议,代码如下:

# ----- twisted ----------
class _WebSocketClientProtocol(WebSocketClientProtocol):
    def __init__(self, factory):
        self.factory = factory

    def onOpen(self):
        #log.debug("Client connected")
        self.factory.protocol_instance = self
        self.factory.base_client._connected_event.set()

class _WebSocketClientFactory(WebSocketClientFactory):
    def __init__(self, *args, **kwargs):
        WebSocketClientFactory.__init__(self, *args, **kwargs)
        self.protocol_instance = None
        self.base_client = None

    def buildProtocol(self, addr):
        return _WebSocketClientProtocol(self)
# ------ end twisted -------
lass BaseWBClient(object):

    def __init__(self, websocket_settings):
        #self.settings = websocket_settings
        # instance to be set by the own factory
        self.factory = None
        # this event will be triggered on onOpen()
        self._connected_event = threading.Event()
        # queue to hold not yet dispatched messages
        self._send_queue = Queue.Queue()
        self._reactor_thread = None

    def connect(self):

        log.msg("Connecting to host:port")
        self.factory = _WebSocketClientFactory(
                                "ws://host:port",
                                debug=True)
        self.factory.base_client = self

        c = connectWS(self.factory)

        self._reactor_thread = threading.Thread(target=reactor.run,
                                               args=(False,))
        self._reactor_thread.daemon = True
        self._reactor_thread.start()

    def send_message(self, body):
        if not self._check_connection():
            return
        log.msg("Queing send")
        self._send_queue.put(body)
        reactor.callFromThread(self._dispatch)

    def _check_connection(self):
        if not self._connected_event.wait(timeout=10):
            log.err("Unable to connect to server")
            self.close()
            return False
        return True

    def _dispatch(self):
        log.msg("Dispatching")
        while True:
            try:
                body = self._send_queue.get(block=False)
            except Queue.Empty:
                break
            self.factory.protocol_instance.sendMessage(body)

    def close(self):
        reactor.callFromThread(reactor.stop)

import time
def Ppippo(coda):
        while True:
            coda.send_message('YOOOOOOOO')
            time.sleep(5)

if __name__ == '__main__':

    ws_setting = {'host':'', 'port':}

    client = BaseWBClient(ws_setting)

    t1 = threading.Thread(client.connect())
    t11 = threading.Thread(Ppippo(client))
    t11.start()
    t1.start()

前面的代码工作正常,但我需要翻译它以在 WAMP 协议 insted websocket 上运行。

有人知道我是怎么解决的吗?

【问题讨论】:

  • thread1.join() 下移到thread2.join()。在其当前位置,它会告诉主线程等到 thread1 死亡。由于您无法终止线程(无需使用 Ctrl-C 终止整个进程),因此永远不会创建第二个线程。
  • 另外,你的线程应该在线程的.run() 函数中完成它们的工作。 join() 在主函数结束时创建一个线程,以便线程有时间在主应用程序退出之前完成它们的执行。所以你需要有一种方法让线程完成它们的任务。
  • 您需要 2 个应用会话,还是真的需要 2 个线程?如果是前者,两个会话是同一个路由器/领域还是不同的?如果是后者,为什么首先需要线程?如果你需要做例如CPU 密集型的东西,想使用多核,请告诉我们。需要更多“为什么”和“什么”...
  • oberstet 感谢您的回复。我已经用更多细节修改了这个问题。

标签: python websocket twisted autobahn wamp-protocol


【解决方案1】:

坏消息是 Autobahn 正在使用 Twisted 主循环,因此您不能同时在两个线程中运行它。

好消息是你不需要在两个线程中运行它来运行两个东西,而且两个线程无论如何都会更复杂。

启动多个应用程序的 API 有点混乱,因为您有两个 ApplicationRunner 对象,乍一看,您在高速公路上运行应用程序的方式是调用 ApplicationRunner.run

然而,ApplicationRunner 只是一种方便,它包含了设置应用程序的内容和运行主循环的内容;真正的工作发生在WampWebSocketClientFactory

为了实现你想要的,你只需要摆脱线程,自己运行主循环,让ApplicationRunner实例简单地设置他们的应用程序。

为了实现这一点,您需要更改程序的最后一部分来执行此操作:

class ManageRemoteSystem:
    def __init__(self):
        self.runner = ApplicationRunner(url=wampAddress, realm=wampRealm)

    def start(self):
        # Pass start_reactor=False to all runner.run() calls
        self.runner.run(AutobahnMRS, start_reactor=False)


class InternalMessages:
    def __init__(self):
        self.runner = ApplicationRunner(url=wampAddress, realm=wampRealm)

    def start(self):
        # Same as above
        self.runner.run(AutobahnIM, start_reactor=False)


if __name__ == '__main__':
    server = ManageRemoteSystem()
    sendMessage = InternalMessages()
    server.start()
    sendMessage.start()

    from twisted.internet import reactor
    reactor.run()

【讨论】:

  • API 有点糟糕,是的,尤其是对于这个用例。我们在另一个 repo 中有未发布的东西,它允许通过一个返回 DeferredList 的调用来启动多个会话(这与单个 WAMP 应用程序会话一起解决。)可能这应该在 Autobahn ..
  • 对不起,oberstet,你能不能更准确地说明这一点
  • 谢谢@Glyph!!!我一直在寻找 start_reactor 参数的年龄,但似乎在文档中没有提及它......或者如何将高速公路添加到现有的 Twisted 应用程序?
  • @jjmontes - 我很确定这是唯一的方法。用于更新的错误 oberstet ;-)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
  • 1970-01-01
  • 2020-09-03
  • 1970-01-01
  • 2020-04-04
  • 2015-06-22
  • 2021-12-18
相关资源
最近更新 更多