简体   繁体   English

带有TCPServer的扭曲应用程序(.tac)无法正常工作,而常规Twisted .py可以与listenTCP一起使用

[英]twistd Application (.tac) with TCPServer not working, while regular Twisted .py works with listenTCP

I currently trying to convert an application based on twisted to the twistd Twisted Application framework (TAC). 我目前正在尝试将基于扭曲的应用程序转换为扭曲的扭曲应用程序框架(TAC)。

The application works if I start the .py, but not with the "twistd -noy zmq2tcp.tac" daemon. 如果启动.py,则该应用程序可以运行,但不能使用“ twistd -noy zmq2tcp.tac”守护程序启动。 The ZMQ connections seems properly opened, but if started with the tac file it does not Listen on port 2323. ZMQ连接似乎已正确打开,但是如果以tac文件开头,则它不会在端口2323上侦听。

Please explain me the reason why in this case the listenTCP works but not the internet.TCPServer 请解释一下为什么在这种情况下listenTCP起作用但不能在Internet上起作用的原因。

The zmq2tcp.tac file: zmq2tcp.tac文件:

#!/usr/bin/python
# **- encoding: utf-8 -**
from twisted.application import internet, service
from twisted.application.service import Application

from txzmq import ZmqFactory, ZmqEndpoint, ZmqSubConnection, ZmqPushConnection

from zmq2tcp import *

LISTEN_PORT = 2323

class ListenService(service.Service):
    def __init__(self):
        self.zf = ZmqFactory()
        self.minidoFactory = MinidoServerFactory()

    def startService(self):
        self.sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
        self.push = ZmqEndpoint('connect', 'tcp://localhost:5558')
        self.subconn = ZmqSubConnection(self.zf, self.sube)
        self.subconn.subscribe('')

        # Create the resource
        self.minidoFactory.pushconn = ZmqPushConnection(self.zf, self.push)
        self.subconn.gotMessage = self.minidoFactory.send2tcp
        return internet.TCPServer(LISTEN_PORT, self.minidoFactory)

    def stopService(self):
        del self.sube
        del self.push
        del self.subconn

application = Application('ZMQ2TCP')
service = ListenService()
service.setServiceParent(application)

The zmq2tcp.py file: zmq2tcp.py文件:

#!/usr/bin/env python
# **- encoding: utf-8 -**
"""
    Minido-Unleashed is a set of programs to control a home automation
    system based on minido from AnB S.A.

    Please check http://kenai.com/projects/minido-unleashed/

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    ***

    This program connects to a STOMP server, and allow dual way communication
    with the minido bus, checking the validity of the packet before sending.
"""

###############################################################################
from __future__ import print_function
from twisted.application import internet, service
from twisted.internet.protocol import Protocol, ReconnectingClientFactory
from twisted.internet.protocol import Factory


# Other imports
import datetime
import time
import sys
import msgpack

# minido
from protocol import *

# txZMQ
from txzmq import ZmqFactory, ZmqEndpoint, ZmqPubConnection, ZmqSubConnection, ZmqPushConnection

MINIDO_LISTEN_PORT = 2323 

class MinidoServerFactory(Factory):
    def __init__(self):   
        self.connections = []

    def startedConnecting(self, connector):
        print('Started to connect.')

    def buildProtocol(self, addr):
        return MinidoProtocol(self)

    def clientConnectionLost(self, connector, reason):
        print('Lost connection.  Reason:', reason)
        ReconnectingClientFactory.clientConnectionLost(self, connector, reason)

    def clientConnectionFailed(self, connector, reason):
        print('Connection failed. Reason:', reason)
        ReconnectingClientFactory.clientConnectionFailed(self, connector,
                                                         reason)
    def recv_message(self, message):
        print(': TCP to STOMP : %s' % (' '.join(map(lambda i: '{0:02X}'.format(i),message))))
        pushconn.push(msgpack.packb(message))

    def send2tcp(self, rawmessage, tag):
        message = msgpack.unpackb(rawmessage)
        if type(message) is tuple:
            print(": STOMP to %i TCP client(s) : %s" % (
                len(self.connections),
                ' '.join(map(lambda i: '{0:02X}'.format(i),message))))
            for conn in self.connections:
                conn.send_data(message)

if __name__ == '__main__':
    from twisted.internet import reactor
    zf = ZmqFactory()
    minidoFactory = MinidoServerFactory()
    sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
    subconn = ZmqSubConnection(zf, sube)
    subconn.subscribe('') 

    subconn.gotMessage = minidoFactory.send2tcp

    push = ZmqEndpoint('connect', 'tcp://localhost:5558')
    minidoFactory.pushconn = ZmqPushConnection(zf, push)
    reactor.listenTCP(MINIDO_LISTEN_PORT, minidoFactory)
    reactor.run()

The problem is that in your ListenService.startService you are creating and returning a TCPServer service, but you are not starting that service. 问题在于,您在ListenService.startService正在创建并返回 TCPServer服务,但是您没有启动该服务。

IService.startService does not return a value, so rather than return internet.TCPServer(LISTEN_PORT, self.minidoFactory) , do internet.TCPServer(LISTEN_PORT, self.minidoFactory).startService() . IService.startService不返回值,而是return internet.TCPServer(LISTEN_PORT, self.minidoFactory)而不是internet.TCPServer(LISTEN_PORT, self.minidoFactory).startService()

This has an obvious problem though, which is that your stopService will then not remember where that TCPServer is to stop it later. 但是,这有一个明显的问题,那就是您的stopService将不记得该TCPServer稍后将其停止的位置。 It would be better to factor this to create the TCPServer as soon as possible, and start/stop it along with your service, like this: 最好考虑将此因素尽快创建 TCPServer ,并与您的服务一起启动/停止它,如下所示:

class ListenService(service.Service):
    def __init__(self):
        self.zf = ZmqFactory()
        self.minidoFactory = MinidoServerFactory()
        self.tcpService = internet.TCPServer(LISTEN_PORT, self.minidoFactory)

    def startService(self):
        self.sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
        self.push = ZmqEndpoint('connect', 'tcp://localhost:5558')
        self.subconn = ZmqSubConnection(self.zf, self.sube)
        self.subconn.subscribe('')

        # Create the resource
        self.minidoFactory.pushconn = ZmqPushConnection(self.zf, self.push)
        self.subconn.gotMessage = self.minidoFactory.send2tcp
        self.tcpService.startService()

    def stopService(self):
        del self.sube
        del self.push
        del self.subconn
        return self.tcpService.stopService()

First, a big thank you for this perfect answer. 首先,非常感谢您的完美回答。 Below is the workaround I found that is also working. 以下是我发现也可行的解决方法。 But I do not fully understand the below solution and prefer your solution and explanation so I'll flag it as THE ONE. 但是我不完全理解以下解决方案,而是喜欢您的解决方案和说明,因此我将其标记为“一体”。

#!/usr/bin/python
# **- encoding: utf-8 -**
from twisted.application import internet, service
from twisted.application.service import Application
from twisted.internet import reactor

from txzmq import ZmqFactory, ZmqEndpoint, ZmqSubConnection, ZmqPushConnection

from zmq2tcp import *

LISTEN_PORT = 2323

class ListenService(service.Service):
    def __init__(self):
        self.zf = ZmqFactory()
        self.minidoFactory = MinidoServerFactory()

    def startService(self):
        self.sube = ZmqEndpoint('connect', 'tcp://localhost:5557')
        self.push = ZmqEndpoint('connect', 'tcp://localhost:5558')
        self.subconn = ZmqSubConnection(self.zf, self.sube)
        self.subconn.subscribe('')

        # Create the resource
        self.minidoFactory.pushconn = ZmqPushConnection(self.zf, self.push)
        self.subconn.gotMessage = self.minidoFactory.send2tcp
        self._port = reactor.listenTCP(LISTEN_PORT, self.minidoFactory)

    def stopService(self):
        del self.sube
        del self.push
        del self.subconn

application = Application('ZMQ2TCP')
service = ListenService()
service.setServiceParent(application)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM