如何从运行在QThread中的服务器捕获信号

问题描述

我有2个课程:

  • 服务器
  • 虚拟课程

我需要能够从Blender之类的程序中运行此程序。由于 server 需要不断侦听任何请求,因此我需要在单独的线程中运行它,否则它将阻塞主UI。 虚拟需要在主线程中运行。

服务器收到请求后,它需要发出一个信号,该信号将被虚拟捕获。但是,无论我如何尝试,我似乎都无法捕捉到来自服务器的信号。

以下是一些无需Blender即可运行的示例代码

服务器虚拟

import wsgiref.simple_server
import json
from pyside2.QtCore import *

class DummyClass(QObject):
    def __init__(self):
        super(DummyClass,self).__init__()
        print("Started the dummy")

    def catch_dummy_signal(self,name,dictionary):
        print(name)
        print(dictionary)
        print("I CAUGHT THE DUMMY SIGNAL")


class Server(QObject):
    DUMMY_SIGNAL = Signal(str,dict)
    def __init__(self):
        super(Server,self).__init__()

    def start_listening(self):
        simple_server = wsgiref.simple_server.make_server("127.0.0.1",65500,self.process_request)
        print(simple_server.server_address)
        while True:
            simple_server.handle_request()

    def process_request(self,environ,start_response):
        print("Got request")
        status = "200 OK"
        headers = [("Content-type","text/plain")]
        start_response(status,headers)
        request_body_size = int(environ.get('CONTENT_LENGTH',0))
        request_body = environ['wsgi.input'].read(request_body_size)
        query = json.loads(request_body)

        print("Emitting dummy signal")
        self.DUMMY_SIGNAL.emit("Luke Skywalker",{"occupation": "Jedi Knight"})

        command_result = {"query": query}
        return [json.dumps(command_result).encode()]

if __name__ == '__main__':
    server = Server()
    dummy = DummyClass()

    server.DUMMY_SIGNAL.connect(dummy.catch_dummy_signal)

    thread = QThread()
    server.movetoThread(thread)
    thread.started.connect(server.start_listening)
    thread.start()


    # running an endless loop here,otherwise the program ends. This endless loop will not be used when running it inside a program like Blender
    while True:
        pass

此客户端代码可用于调用向发出DUMMY_SIGNAL的服务器的请求,以供虚拟捕获:

import requests
url = "http://127.0.0.1:65500"
payload = {"data": "This is important data!"}

response = requests.post(url,json=payload).json()
print(response)

服务器输出如下:

Started the dummy
('127.0.0.1',65500)
got request
Emitting dummy signal
127.0.0.1 - - [01/Oct/2020 16:19:33] "POST / HTTP/1.1" 200 46

客户端的输出如下:

{'query': {'data': 'This is important data!'}}

从服务器的输出中可以看到,catch_dummy_signal的打印语句未显示。因此,我必须假设该函数从未被调用

如何通过向服务器发出请求来触发catch_dummy_signal

解决方法

仅当存在Qt eventloop时,信号才起作用,因为它是一种传输手段,在您的情况下,使用QCoreApplication就足够了:

if __name__ == "__main__":

    app = QCoreApplication([])
    server = Server()
    dummy = DummyClass()

    server.DUMMY_SIGNAL.connect(dummy.catch_dummy_signal)

    thread = QThread()
    server.moveToThread(thread)
    thread.started.connect(server.start_listening)
    thread.start()

    app.exec_()