从另一个线程(子线程)访问QTcpSocket

时间:2014-01-13 07:51:21

标签: c++ qt qthread qtcore qtnetwork

我创建了一个包含QTcpServer的线程,它接受任何传入的连接:

void Service::run() //Service class is a subclass of QThread
{
    server->listen(QHostAddress::LocalHost, ServicePortNo);
    // server is a private member of Service    

    while(server->waitForNewConnection(-1)){
        QTcpSocket *socket = server->nextPendingConnection();
        handle(socket); // This is a pure virtual function
    }
}
handle(QTcpSocket *socket)中的

// TimeDateService is subclass of Service
// implementation of pure virtual function handle()
void TimeDateService::handle(QTcpSocket *socket)
{
    (new TimeDateSocketHandler(socket))->Start();
}

注意TimeDateSocketHandlerSocketHandler的子类,SocketHandler本身是QThread的子类,如下所示:

void SocketHandler::run()
{
    if(!socket->waitForReadyRead(WAIT_TIMEOUT))
    {
        socket->disconnectFromHost();
        socket->close();
        return;
    }
    QByteArray request = socket->readAll();
    QByteArray response = Serve(request); // Serve is a pure virtual function
    socket->write(response);
    socket->waitForBytesWritten(WAIT_TIMEOUT);
    socket->disconnectFromHost();
    socket->close();
}

最后这里是TimeDateSocketHandler

QByteArray TimeDateSocketHandler::Serve(QByteArray request)
{
    QByteArray response;
    response.append(QTime::currentTime().toString().toUtf8());
    response.append(QString(SEPARATOR).toUtf8());
    response.append(QDate::currentDate().toString().toUtf8());
    return response;
}

主要功能:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    TimeDateService timedateService;
    //CalculatorService calculatorService;
    //RemoteCMDService remoteCMDService;

    timedateService.StartService();
    //calculatorService.StartService();
    //remoteCMDService.StartService();

    return a.exec();
}

main函数中,我启动了TimeDateService。但是当我连接到服务器以检索时间和日期时,服务器发送时间和日期,但是当TimeDateSocketHandler想要关闭套接字时程序崩溃:

  

QCoreApplication :: sendEvent中的ASSERT失败:“无法发送事件   由不同线程拥有的对象。当前线程3998779bf0。   接收器''(类型'QNat iveSocketEngine')是在线程中创建的   39985efcd0“,文件内核\ qcoreapplicatio n.cpp,第494行

任何人都可以帮助我,我该如何解决这个问题,非常感谢

1 个答案:

答案 0 :(得分:1)

你的问题就在这一行:

(new TimeDateSocketHandler(socket))->Start();

父“套接字”存在于TimeDateService线程中,但子进程将位于TimeDateocketHandler线程中。使用Qt事件循环时,父级和子级应位于同一个线程中。

以下是documentation的相关部分:

  

所有线程都支持事件过滤器,但监视对象必须与受监视对象位于同一个线程中。类似地,QCoreApplication :: sendEvent()(与postEvent()不同)只能用于将事件分派给生成在调用函数的线程中的对象。这是一个例子:

解决方案相对简单:

  • 您可以使用invokeMethod method of QMetaObject直接调用该方法。您需要使用排队连接来获取在单独的线程中触发的插槽。

    QMetaObject :: invokeMethod(new TimeDateSocketHandler(socket),                           SLOT(开始()),                           Qt的:: QueuedConnection);

  • 使用信号和插槽。这意味着发出信号而不是直接调用,然后连接另一个线程的相应插槽。

    TimeDateSocketHandler * timeDateSocketHandler = new TimeDateSocketHandler(socket);

    connect(this,SIGNAL(socketHandled()),timeDateSocketHandler,SLOT(Start()));

    发出socketHandled();

  • 使用智能指针(如QSharedPointer)代替原始指针

  • 移动到套接字处理到另一个线程。