-
常规用法
- 创建服务器QTcpServer对象;
- 服务器对象开启监听QTcpServer::listen();
- QTcpServer::newconnection()信号关联到自定义槽函数;
- 槽函数中调用QTcpServer::nextpendingconnection()函数得到客户端连接的QTcpSocket对象;
- 使用QTcpSocket对象与客户端通信。
-
多线程用法
基于多线程的用法有两种,第一种是子类化QThread,重写run函数,在run函数中用while或for语句实现多线程业务;第二种是使用事件循环实现多线程。本文介绍第二种使用方法。
- 自定义QObject子类Object处理服务端需要多线程完成的业务,比如网络数据的收发;
- 自定义QTcpServer子类TcpServer,子类中重写函数 incomingConnection(qintptr socketDescriptor);
- 创建服务器子类TcpServer对象;
- 服务器对象开启监听TcpServer::listen();
- TcpServer子类的incomingConnection(qintptr socketDescriptor)函数中处理接收到的网络连接信息socketDescriptor,将socketDescriptor参数传递给Object对象,并将QThread对象MoveToThread到Object对象中,到此可以放心的使用信号和槽实现多线程通信;
- 在Object类中使用socketDescriptor信息定义QTcpSocket套接字对象;
- 使用套接字对象在Object中与客户端通信。
多线程用法关键代码:
void TcpServer::incomingConnection(qintptr socketDescriptor)
{//多线程网络连接,每个新的网络连接用一个新的线程管理
QString slog = QString("TcpServer ThreadID::%1").arg(qint64(QThread::currentThreadId()));
logInfo(slog);
m_pThread = new QThread;
m_pObject = new TcpServerObject();
m_pObject->moveToThread(m_pThread);
connect(this,SIGNAL(sigInitSocket(qint32)),m_pObject,SLOT(initSocket(qint32)));
connect(m_pObject,SIGNAL(sigNewTime(QString)),this,SLOT(onNewTime(QString)));
connect(this,SIGNAL(sigSendData()),m_pObject,SLOT(sendData()));
m_pThread->start();
emit sigInitSocket(socketDescriptor);
}
void TcpServerObject::initSocket(qint32 socketDescriptor)
{
m_pTcpSocket = new QTcpSocket;
if(!m_pTcpSocket->setSocketDescriptor(socketDescriptor))
{
logError(m_pTcpSocket->errorString());
return;
}
connect(m_pTcpSocket,SIGNAL(readyRead()),this,SLOT(recvData()));
}
如下图所示,TcpServer 的ThreadID(即主线程ID:20748)与Object::recvData的 ThreadId、Object::sendData的 ThreadId (即次线程ID:21112)确实不同。因此可以将大量的耗时的业务放在Object类中实现。
注:在基于事件循环的多线程使用方法中,不要在Object的构造函数中作初始化,否则会告警: