QTcpSocket:消息不是从另一个线程发送的

QTcpSocket: message not send from another thread

本文关键字:线程 另一个 消息 QTcpSocket      更新时间:2023-10-16

我知道这个主题已经有很多主题了,但没有人能纠正我的问题。。。我希望有人能找到解决办法。

主题:我正在开发一个多线程游戏服务器。然后,我重载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(("时,不会发出任何消息,我有一条著名的消息:"QSocketNotificationer:套接字通知程序无法从另一个线程启用或禁用"。我知道我有这个消息,因为"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时(在ready read事件上写入-是预期的吗,执行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();
}