简体   繁体   English

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

[英]Access QTcpSocket from another thread (child thread)

I have created a thread contains a QTcpServer which accepts any incoming connections: 我创建了一个包含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
    }
}

in handle(QTcpSocket *socket) : handle(QTcpSocket *socket)

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

Note : TimeDateSocketHandler is a subclass of SocketHandler and SocketHandler itself is a subclass of QThread as shown in the following: 注意TimeDateSocketHandler是的一个子类SocketHandlerSocketHandler本身的一个子类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();
}

And finally here is the TimeDateSocketHandler 最后是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;
}

main function: 主功能:

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();
}

In the main function I started the TimeDateService . main功能中,我启动了TimeDateService But when I connect to the server for retrieving time and date, server sends time and date but when the TimeDateSocketHandler wants to close the socket the program crashes: 但是,当我连接到服务器以获取时间和日期时,服务器发送时间和日期,但是当TimeDateSocketHandler要关闭套接字时,程序崩溃:

ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects ow ned by a different thread. Current thread 3998779bf0. Receiver '' (of type 'QNat iveSocketEngine') was created in thread 39985efcd0", file kernel\\qcoreapplicatio n.cpp, line 494 QCoreApplication :: sendEvent中的ASSERT失败:“无法将事件发送到其他线程所拥有的对象。在线程39985efcd0中创建了当前线程3998779bf0.Receiver(类型为'QNat iveSocketEngine')”,文件kernel \\ qcoreapplicatio n.cpp ,第494行

Can anyone help me out please how can I fix this problem, Many Thanks 任何人都可以帮我吗,我该如何解决这个问题,非常感谢

Your problem is this line: 您的问题是这一行:

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

The parent "socket" lives in the TimeDateService thread, but the child will be in the TimeDateocketHandler thread. 父“套接字”位于TimeDateService线程中,而子“套接字”位于TimeDateocketHandler线程中。 Parent and children should be in the same thread when using the Qt event loop. 使用Qt事件循环时,父级和子级应该在同一线程中。

Here is the relevant part of the documentation : 这是文档的相关部分:

Event filters are supported in all threads, with the restriction that the monitoring object must live in the same thread as the monitored object. 所有线程均支持事件过滤器,但限制是监视对象必须与被监视对象位于同一线程中。 Similarly, QCoreApplication::sendEvent() (unlike postEvent()) can only be used to dispatch events to objects living in the thread from which the function is called. 同样,QCoreApplication :: sendEvent()(与postEvent()不同)只能用于将事件调度到存在于调用该函数的线程中的对象。 Here is an example of that: 这是一个例子:

The solution is relatively straight-forward: 解决方案相对简单:

  • You could call the method directly with the invokeMethod method of QMetaObject . 您可以使用QMetaObjectinvokeMethod方法直接调用该方法。 You would need to use queued connection to get the slot triggered in the separate thread. 您将需要使用排队连接来在单独的线程中触发插槽。

    QMetaObject::invokeMethod(new TimeDateSocketHandler(socket), SLOT(Start()), Qt::QueuedConnection); QMetaObject :: invokeMethod(新的TimeDateSocketHandler(socket),SLOT(Start()),Qt :: QueuedConnection);

or 要么

  • Use signal and slots. 使用信号和插槽。 This means emit a signal instead of direct invokation and then connect the other thread's corresponding slot. 这意味着发出信号而不是直接调用,然后连接另一个线程的相应插槽。

    TimeDateSocketHandler *timeDateSocketHandler = new TimeDateSocketHandler(socket); TimeDateSocketHandler * timeDateSocketHandler = new TimeDateSocketHandler(socket);

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

    emit socketHandled(); 发出socketHandled();

or 要么

  • Use a smart pointer (like QSharedPointer) instead of raw pointer 使用智能指针(如QSharedPointer)代替原始指针

  • Move to the socket handling into the other thread. 移动到另一个线程的套接字处理。

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

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