TCP服务端的经典案例中有个例子,就是当收到TCP客户端连接后,线程池直接开一个线程然后把这个socket指针传到线程里面,依靠新开的线程进程业务处理。
但在Qt里面使用这个方式后,会报一个QTcpSocket不能跨线程调用的问题。
问题描述是这样的:
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
查了下百度,都是n年前的技术(本博文写于2021-08-11 09:15:25,此博文发布到网上应该是1个月以后,笔记太多了,每星期公布6篇笔记),用信号与槽机制将业务处理放到新线程中,TCP操作用信号让以前的线程发送数据,通过这种方式解决问题!但如果这样做,代码就不够优雅了,甚至还有点烂。一个新技术框架和老技术做对比,应该是取其精华去其糟粕,而不是越来越复杂。不然这个新技术将毫无意义。
花了半天时间查阅了官方资料,最后得出了QTcpSocket跨线程调用的方式。
首先继承QTcpServer重写incomingConnection(qintptr handle)
当这个handle此时套接字的描述符号。把这个传给线程,子线程生成一个QTcpScoket然后利用setSocketDescriptor使得这个socket获得到收发数据的能力。
实例如下:
QTcpServer相关:
void HttpsServer::incomingConnection(qintptr socketDescriptor)
{
QThreadPool::globalInstance()->start(new HttpsThread(socketDescriptor));
}
QRunnable相关:
HttpsThread::HttpsThread(qintptr descriptor)
{
m_socketDescriptor = descriptor;
}
这个m_socketDescriptor直接为int型就可以了。
这样run()中调用setSocketDescriptor,进行读写操作就不会有跨线程的问题了。
void HttpsThread::run()
{
QTcpSocket tcpSocket;
if(!tcpSocket.setSocketDescriptor(m_socketDescriptor)) {
qDebug() << "tcpSocket.setSocketDescriptor(m_socketDescriptor) failed";
return;
}
tcpSocket.write("Hello Wold");
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
}