在server端中添加心跳机制,15秒后无数据包时判断客户端状态为断开连接。
在clientthread.cpp中使用定时器时,在run函数中初始化了定时器,在槽函数中stop了定时器。但是会报QObject::killTimer: Timers cannot be stopped from another thread;
原因是,run函数是属于子线程的,而槽函数不属于。但是要如何在槽函数中关闭定时器呢?(错误处代码在最后面)
///clientthread.cpp
#include "clientthread.h"
ClientThread::ClientThread(qintptr socketDescriptor, QObject *parent) : QThread(parent)
{
m_socketDescriptor=socketDescriptor;
}
void ClientThread::run()
{
m_socket=new QTcpSocket;
m_timer=new QTimer;
m_timer->setInterval(1000);
m_socket->setSocketDescriptor(m_socketDescriptor);
connect(m_socket,SIGNAL(readyRead()),this,SLOT(readSlot()));
connect(m_timer,SIGNAL(timeout()),this,SLOT(doheart()));
m_timer->start();
exec();
}
void ClientThread::readSlot()
{
count=0;//有数据包时,重置心跳数
QByteArray ricvByte=m_socket->readAll();
QString str=ricvByte.toStdString().c_str();
qDebug()<<str;
QStringList strlist=str.split("$");
if(strlist[0]=="heartPackage")//区分消息类型
{
qDebug()<<"this is heart Package";
}
else {
qDebug()<<"this is msg Package";
}
}
//心跳执行与判断,15秒无数据包判断为断开连接
void ClientThread::doheart()
{
count++;
qDebug()<<count;
if(count>15)
{
qDebug()<<"客户端断开连接("<<m_socketDescriptor<<")";
count=0;
m_timer->stop();//这里使用定时器会报QObject::killTimer: Timers cannot be stopped from another thread
}
}
QThread对象本身不在QThread表示的线程里,只有run函数在子线程里跑
所以doheart是跑在Server所在线程里的,而m_timer在QThread所表示的线程里,导致报错
最好的解决方案:ClientThread不再继承QThread,改为继承QObject,run变为槽函数,并添加Signal started()
创建线程的代码(在server中的incomingConnection函数里)改成下面这样
- ClientThread *clt = new ClientThread;
- QThread *th = new QThread(this);
- clt->moveToThread(th);
- connect(clt, &ClientThread::started, clt, &ClientThread::run, Qt::QueuedConnection);
- connect(th, &QThread::finished, clt, &ClientThread::deleteLater);
- th->start();
- emit clt->started();
run函数中所有创建的QObject子类都带上parent,这样可以在deleteLater时一并销毁。