繁体   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-2024 STACKOOM.COM