Qt QTcpSocket 客户端设计(自动重连、多线程处理、发送大数据包、同步方式)
1.頭文件
#ifndef TCPTOOL_H #define TCPTOOL_H#include <QObject> #include <QTcpSocket> #include <QHostAddress>class TCPTool : public QObject {Q_OBJECT//單例模式 private:TCPTool(); public:static TCPTool * GetInstance(){static TCPTool instance;return &instance;}~TCPTool();//變量 private:bool m_exitThread;QTcpSocket * m_tcpClient;bool m_isConnected;//函數(shù) public:bool SendLargeData(QByteArray & block);private:void ProcessThread();bool Connect(const QString & address,int port);signals:void TryConnectSignal();public slots:void Disconnected();void ReadMessage();void TryConnectSlot(); };#endif // TCPTOOL_H2.源代碼
#include "tcptool.h" #include <thread> #include "setting.h"//設(shè)置頭文件TCPTool::TCPTool() {m_tcpClient = new QTcpSocket(this);m_tcpClient->abort();//取消原有連接connect(this,SIGNAL(TryConnectSignal()),this,SLOT(TryConnectSlot()));connect(m_tcpClient,SIGNAL(readyRead()),this,SLOT(ReadMessage()));connect(m_tcpClient,SIGNAL(disconnected()),this,SLOT(Disconnected()));m_isConnected = false;m_exitThread = false;std::thread sendThread(&TCPTool::ProcessThread,this);sendThread.detach(); }TCPTool::~TCPTool() {Disconnected();m_exitThread = true; }bool TCPTool::SendLargeData(QByteArray & block) {if(!m_isConnected)return false;//分包發(fā)送const int PayloadSize = 64*1024;//一個(gè)幀數(shù)據(jù)包大小int totalSize = block.size();int bytesWritten = 0;int bytesToWrite = totalSize;while(bytesWritten<totalSize){int startIdx = bytesWritten;int length = std::min(PayloadSize,bytesToWrite);if(startIdx+length>totalSize)return false;QByteArray smallBlock = block.mid(startIdx,length);qint64 written = m_tcpClient->write(smallBlock);bool success = m_tcpClient->waitForBytesWritten();if(!success)//發(fā)送失敗包時(shí),停止發(fā)送return false;bytesWritten+=written;bytesToWrite-=written;}m_tcpClient->flush();return true; }void TCPTool::ProcessThread() {while(m_exitThread==false){//重連嘗試if(!m_isConnected){emit TryConnectSignal();usleep(200000);//等待連接嘗試if(!m_isConnected){usleep(5000000);//等待5秒重連continue;}}//執(zhí)行發(fā)送(未展開(kāi),思路:大塊數(shù)據(jù)從隊(duì)列讀出,然后在線程中執(zhí)行同步發(fā)送)//SendLargeData(data);usleep(1000000);//等待1s} }bool TCPTool::Connect(const QString & address, int port) {if(!m_tcpClient){m_isConnected = false;return false;}//直接讀取狀態(tài),如果連接正常,則直接返回if(m_tcpClient->state()== QAbstractSocket::ConnectedState){if(m_tcpClient->isValid()){m_isConnected = true;return true;}else{m_isConnected = false;return false;}}//嘗試連接m_tcpClient->abort();//取消原有連接m_tcpClient->connectToHost(address,port);if(m_tcpClient->waitForConnected(1000)){m_isConnected = true;}elsem_isConnected = false;return m_isConnected; }void TCPTool::Disconnected() {m_isConnected = false;if(!m_tcpClient)return;if(m_tcpClient->state()== QAbstractSocket::UnconnectedState||m_tcpClient->waitForDisconnected(1000))return; }void TCPTool::ReadMessage() {QByteArray buf = m_tcpClient->readAll();//讀取數(shù)據(jù) }void TCPTool::TryConnectSlot() {Connect(Setting_Server_IPAddress,Setting_Server_IPPort); }3.說(shuō)明
3.1.自動(dòng)重連
使用waitForConnected時(shí)會(huì)有等待時(shí)間,如果放在主線程中,會(huì)造成卡頓。定時(shí)器也不能執(zhí)行等待(一般情況定時(shí)器運(yùn)行在主線程),因此選擇在線程中執(zhí)行重復(fù)連接。
注意:如果在線程中執(zhí)行Connect函數(shù)時(shí),會(huì)引起:
QObject: Cannot create children for a parent that is in a different thread. (Parent is QTcpSocket(0x142f1860), parent’s thread is QThread(0xbbac10), current thread is QThread(0x7fff18001040)
QObject::startTimer: Timers can only be used with threads started with QThread QObject: Cannot create children for a parent that is in a different thread. (Parent is QTcpSocket(0x142f1860), parent’s thread is QThread(0xbbac10), current thread is QThread(0x7fff18001040)
經(jīng)測(cè)試,在線程中調(diào)用connectToHost會(huì)引起如上問(wèn)題。使得發(fā)送、接收信號(hào)都停留在子線程中,只有當(dāng)子線程exec()之后才釋放信號(hào),從而引起接收不到信息(未觸發(fā)readyRead)和發(fā)送不出去信息(write后沒(méi)有立即發(fā)送出去)。
因此代碼中使用信號(hào)、槽執(zhí)行重新連接嘗試。發(fā)送信號(hào)后,等待片刻讀取執(zhí)行結(jié)果。詳見(jiàn)代碼中示例。
3.2.發(fā)送大數(shù)據(jù)包
執(zhí)行write()時(shí),只能發(fā)送一個(gè)小的數(shù)據(jù)包(與系統(tǒng)相關(guān)),大的數(shù)據(jù)包需要進(jìn)行拆分才能進(jìn)行發(fā)送。本文中在線程中使用同步方式發(fā)送大數(shù)據(jù)包,在線程中write()和waitForBytesWritten()配合即可完成同步方式發(fā)送。
以上代碼經(jīng)測(cè)試基本功能完善,僅供參考。
總結(jié)
以上是生活随笔為你收集整理的Qt QTcpSocket 客户端设计(自动重连、多线程处理、发送大数据包、同步方式)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python学习 Day30 正则表达式
- 下一篇: MVC前言