簡體   English   中英

QTcpSocket:消息不從另一個線程發送

[英]QTcpSocket: message not send from another thread

我知道這個主題已經有很多話題了,但是沒人能糾正我的問題。我希望有人能找到解決方案。

主題:我正在開發多線程游戲服務器。 然后,我重載了TcpServer來寫我的等等。

void TcpServerCustomersHandler::incomingConnection(qintptr socketDescriptor)
{
    ThreadCustomer* client = new ThreadCustomer(socketDescriptor);
    connect(client, &ThreadCustomer::finished, client, &ThreadCustomer::deleteLater);
    client->start();
}

我編寫了另一個使QThread重載的類並編寫了我的連接。 在“問題/答案”模式下,它起作用。 我收到消息並回復。

void ThreadCustomer::run()
{
    qDebug() << "Starting thread: " << m_socketDescriptor;
    m_tcpSocket = new QTcpSocket();

    if(!m_tcpSocket->setSocketDescriptor(m_socketDescriptor))
    {
        qCritical() << "Error creation thread:" << m_tcpSocket->errorString();
        return;
    }

    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &ThreadCustomer::onReadyRead_TcpSocket, Qt::DirectConnection);
    connect(m_tcpSocket, &QTcpSocket::disconnected, this, &ThreadCustomer::onDisconnected_TcpSocket, Qt::DirectConnection);
    connect(InstanceManager::instance(), &InstanceManager::readyRead, this, &ThreadCustomer::onReadyRead_InstanceManager);

    exec();
}

void ThreadCustomer::onReadyRead_TcpSocket()
{   
    QByteArray message = m_tcpSocket->readAll();
    //works...
    m_tcpSocket->write(message);
}

但是,由於它是一個游戲服務器,我希望他能夠發送“通知”。 這意味着向玩家發送消息之前不會收到任何消息。 這些通知由單例“ InstanceManager”發送。

void ThreadCustomer::onReadyRead_InstanceManager(QByteArray message)
{
    m_tcpSocket->write(message);
}

這是我的問題。 當調用“ write()”時,沒有消息發出,並且我有一條著名的消息:“ QSocketNotifier:無法從另一個線程啟用或禁用套接字通知程序”。 我知道我有此消息,因為盡管有連接,但還是從另一個線程中調用了“ write()”。

不幸的是,我找不到解決該問題的解決方案。 有人有主意嗎?

好的,感謝@wtom,我找到了第一個基於隊列的解決方案。

我在我的QThread中使用QTimer來處理消息並避免沖突。 為他人:

void ThreadCustomer::run()
{
    qDebug() << "Starting thread: " << m_socketDescriptor;
    m_tcpSocket = new QTcpSocket();

    if(!m_tcpSocket->setSocketDescriptor(m_socketDescriptor))
    {
        qCritical() << "Error creation thread:" << m_tcpSocket->errorString();
        return;
    }

    m_timerWritting = new QTimer();
    connect(m_timerWritting, &QTimer::timeout, this, &ThreadClient::onTimeOut_timerWritting, Qt::DirectConnection);
    m_timerWritting->start(500);

    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &ThreadClient::onReadyRead_TcpSocket, Qt::DirectConnection);
    connect(m_tcpSocket, &QTcpSocket::disconnected, this, &ThreadClient::onDisconnected_TcpSocket, Qt::DirectConnection);
    connect(InstanceManager::instance(), &InstanceManager::readyRead, this, &ThreadClient::onReadyRead_InstanceManager, Qt::QueuedConnection);

    exec();
}

void ThreadCustomer::onReadyRead_InstanceManager(QByteArray message)
{
    m_listMessageToSend.append(message);
}
void ThreadCustomer::onTimeOut_timerWritting()
{
    if(m_listMessageToSend.count() > 0)
    {
        QByteArray message = m_listMessageToSend.takeFirst();
        m_tcpSocket->write(message);
    }
}

我不知道這是否是更好的解決方案,但是可行:)

我不完全記得它是如何完成的,因此它是更多的偽代碼,但關鍵是當您將InstanceManager :: readyRead連接到ThreadCustomer :: onReadyRead_InstanceManager (在就緒讀取事件上寫入-是否要這樣做 ?), ThreadCustomer :: onReadyRead_InstanceManager將在創建ThreadCustomer的線程中執行,該線程執行void TcpServerCustomersHandler :: incomingConnection(qintptr socketDescriptor) 這不是您想要的。 您必須將ThreadCustomer的 線程關聯 更改為執行ThreadCustomer :: run()的線程

編輯 ThreadCustomer是從QThread派生的,對嗎?

void TcpServerCustomersHandler::incomingConnection(qintptr socketDescriptor)
{
    ThreadCustomer* client = new ThreadCustomer(socketDescriptor);
    client->moveToThread(&client); // in canonical way QThread and ThreadCustomer are different objects: client->moveToThread(&thread);, but may be it will work like this?
    connect(client, &ThreadCustomer::finished, client, &ThreadCustomer::deleteLater);
    client->start();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2025 STACKOOM.COM