监控功能完成并与客户交谈

时间:2018-07-12 18:37:39

标签: python twisted

我想我正在做一些异步编程之类的事情,我不确定如何解决这个问题。我有一个function X在新线程上运行,在主线程上有扭曲的tcp服务器。我想在function X完成其工作时向客户端传递一条消息。代码看起来像这样:

val = None

def x():
    global val
    #do something to val and send message to client that val is ready

class Server(protocol.Protocol):
    def connectionMade(self):
        self.transport.write(b'REDPY*')

    def dataReceived(self, data):
        print("Packet: ",data)


class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        print("new client")
        return Server()

threading.Thread(target=x).start()

endpoints.serverFromString(reactor, "tcp:1235").listen(EchoFactory())
reactor.run()

我研究了延迟处理和事件处理中的延迟,我不确定使用什么。

2 个答案:

答案 0 :(得分:1)

将消息从一个任务传递到另一任务,然后再通过网络传递给客户端是很棘手的。当涉及到线程时,就好像您在“暮光之城”中工作:)除了开玩笑之外,这是一个基于您的示例的简单代码段:

from queue import Queue, Empty
import threading

from twisted.internet import endpoints, protocol, reactor, task


def x(shutdown_event, queue):
    while not shutdown_event.is_set():
        # do something to val and send message to client that val is ready
        queue.put(b'data')

    print('thread done')


class Server(protocol.Protocol):
    def connectionMade(self):
        # append client to list in factory
        self.factory.clients.append(self)
        self.transport.write(b'REDPY*')

    def connectionLost(self, reason):
        # remove client from list after disconnection
        self.factory.clients.remove(self)

    def dataReceived(self, data):
        print("Packet: ",data)


class EchoFactory(protocol.Factory):

    protocol = Server

    def __init__(self):
        self.clients = []


def pop_from_queue(queue, factory):
    try:
        data = queue.get(timeout=0.5)

        # process data after this point

        # loop through the clients and send them stuff
        for client in factory.clients:
            # NOTE: ensure the data sent is in bytes
            client.transport.write(data)
    except Empty:
        pass


def main():
    factory = EchoFactory()
    queue = Queue()
    event = threading.Event()

    # when the reactor stops, set Event so that threads know to stop
    reactor.addSystemEventTrigger('before', 'shutdown', event.set)
    # periodically check and pop from the queue
    periodic_task = task.LoopingCall(pop_from_queue, queue, factory)
    periodic_task.start(1)

    threading.Thread(target=x, args=(event, queue)).start()
    endpoints.serverFromString(reactor, "tcp:1235").listen(factory)


main()
reactor.run()

您必须从中获得的基本知识是:

  • 线程之间有一个共享的Queue对象

  • Factory对象包含clients

  • 的列表
  • 消除了buildFactory重载,只需在protocol中设置EchoFactory属性。在这种情况下,您不需要做任何花哨的事情,因此最好保留它。另外,默认情况下,Twisted会在协议中设置self.factory属性。

  • 当客户端将其连接到factory.clients后,客户端将在connectionLost后被删除

  • 有一个LoopingCall任务会定期pop_from_queue

我还添加了一个额外的关闭Event,它是在反应堆关闭时设置的,可以正常关闭线程。如果有任何不清楚的地方,请发表评论,我会做更彻底的解释。

答案 1 :(得分:0)

您基本上是在这里进行多线程编程。在主线程中使用Twisted没关系。您仍然需要一些线程安全的通信原语。 Twisted可能会有所作为的唯一方法是,它提供了一些使用线程来实现目标的工具。您的问题和示例都没有明确说明您的目标是什么,因此我无法在该方向上提供任何指导(因此,下一次,请考虑对您的问题进行更具体和详细的​​介绍,以获取潜在的更好的答案)。

您可以将Queue用作线程安全(-ish)线程间通信机制。

import threading
from Queue import Queue

def x(reactor, queue):
    while True:
        item = queue.get()
        # ... processing

threading.Thread(target=x).start()

# ...
reactor.run()

您还可以跳过长时间运行的线程,而仅使用Twisted的线程池进行短暂的操作。

a_deferred = deferToThread(some_task, ...)
a_deferred.addCallback(deal_with_result_of_task)