You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt中app.exec()机制与ZMQ服务端客户端通信循环实现问题

app.exec()的作用就是启动Qt的主事件循环,确实会一直阻塞直到程序退出才返回,所以你写在它前面的通信逻辑只会执行一次,这是正常现象。

报错原因

虽然QThread本身继承自QObject,但你自定义的MyThread子类使用了Qt的槽函数特性,必须在类定义中添加Q_OBJECT宏,Qt的元对象系统才能正确处理类的信号槽逻辑,缺少这个宏就会触发你遇到的编译错误。另外你当前的线程用法和通信逻辑也有问题,按下面的步骤修改即可实现循环通信:

1. 修改thread.h

#include <QThread>

class MyThread : public QThread{
    Q_OBJECT
protected:
    // run是QThread的内置虚函数,直接重写即可,不需要定义为槽
    void run() override;
};

2. 修改thread.cpp的run实现

void MyThread :: run() {
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REP);
    socket.bind("tcp://*:2424");
    zmq::message_t request;

    // 加死循环,处理完一个请求后继续等待下一个
    while(true) {
        // Wait for next request from client
        cout << "Waiting for the next request ." << endl;
        socket.recv(&request);
        cout << "Waiting for the next request.. " << endl;
        string replyMessage = string(static_cast<char *>(request.data()), request.size());

        // Print out received message
        cout << "Received from client (Python): " + replyMessage << endl;

        sleep(1);

        //  Send reply back to client
        string msgToClient("W");
        zmq::message_t reply(msgToClient.size());
        memcpy((void *) reply.data(), (msgToClient.c_str()), msgToClient.size());
        socket.send(reply);
    }
    // 不需要加exec(),你这里用阻塞recv等待请求,不需要Qt的线程事件循环
}

3. 修改main.cpp中的线程调用逻辑

你之前混淆了QThread的两种使用方式,重写run()的用法不需要moveToThread,直接启动线程即可:

// 替换原来的线程创建代码
MyThread *zmqThread = new MyThread();
zmqThread->start();

注意事项

  • 添加Q_OBJECT宏后,必须清理之前的编译缓存,重新执行qmake再编译,否则还可能出现元对象相关的编译错误。
  • 如果需要把线程中收到的消息传递到UI层更新界面,直接在MyThread中定义信号,触发后通过信号槽传递到主线程即可,Qt的信号槽天生支持跨线程安全通信。
  • 不要在这个子线程中操作任何UI相关的控件,所有UI操作都必须在主线程执行。

内容的提问来源于stack exchange,提问作者noobie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 04:06:06