我知道这个主题已经有很多话题,但是没人可以纠正我的问题... 我希望有人能找到解决方案。
主题:我正在开发多线程游戏服务器。 然后,我重载了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()”。
不幸的是,我找不到解决该问题的解决方案。有人有主意吗?
答案 0 :(得分:0)
好的,感谢@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);
}
}
我不知道这是否是更好的解决方案,但是可行:)
答案 1 :(得分:0)
我不完全记得它是如何完成的,因此它是更多的伪代码,但关键是当您将 InstanceManager :: readyRead 连接到 ThreadCustomer :: onReadyRead_InstanceManager 时(在就绪读取事件上写入-是否有此意图?), ThreadCustomer :: onReadyRead_InstanceManager 将在创建 ThreadCustomer 的线程中执行,该线程执行 void TcpServerCustomersHandler: :incomingConnection(qintptr socketDescriptor)。这不是您想要的。您必须将 ThreadCustomer 的thread affinity更改为执行 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();
}