Qt開發(fā)之使用socket實現(xiàn)遠(yuǎn)程控制
Qt之使用socket實現(xiàn)遠(yuǎn)程控制
在前面的文章中介紹過Qt心跳包的實現(xiàn)方法,本篇文章將會介紹下位機通過心跳包和上位機之間進(jìn)行數(shù)據(jù)交互和遠(yuǎn)程功能控制的實現(xiàn)方法。
首先介紹環(huán)境,下位機使用Qt作為主程序,上下位機使用TCP socket進(jìn)行網(wǎng)絡(luò)通信,上位機實現(xiàn)方式任意。下位機心跳包線程在進(jìn)程一開始就啟動,一直到進(jìn)程結(jié)束才停止。
心跳包是一個始終獨立的線程,首先要搭建框架:
main.cpp
#include <heartbeatthread.h> //心跳包線程 heartbeatThread *ht = nullptr; ht = new heartbeatThread; ht -> start();
.h文件
#ifndef HEARTBEATTHREAD_H #define HEARTBEATTHREAD_H #include <QThread> #include <QCoreApplication> #include <QTimer> #include <QTcpSocket> #include <QHostAddress> #include <QtConcurrent/QtConcurrent> using namespace std; class heartbeatThread : public QThread { Q_OBJECT public: explicit heartbeatThread(QObject *parent = nullptr); void run(); //任務(wù)處理線程 ~heartbeatThread(){ } public slots: private: QTcpSocket *tcpSocket = nullptr; protected: }; #endif // HEARTBEATTHREAD_H
.cpp文件
#include "heartbeatthread.h" heartbeatThread::heartbeatThread(QObject *parent) { } void heartbeatThread::run() { tcpSocket = new QTcpSocket(); tcpSocket->connectToHost(QHostAddress("127.0.0.1"), 5000); QtConcurrent::run([=]() { while(true) { try{ //收包 //將接收內(nèi)容存儲到字符串中 char recvMsg[1024] = {'\0'}; int recvRe = tcpSocket->read(recvMsg, 1024); if(recvRe != 0 && recvRe != -1) //0:連接未發(fā)信息;-1:未連接 { } } catch(...){} QEventLoop eventloop; QTimer::singleShot(1, &eventloop, SLOT(quit())); eventloop.exec(); } }); while(true){ try{ //發(fā)包 //等待連接成功 if(!tcpSocket->waitForConnected(30000)) { tcpSocket->connectToHost(QHostAddress("127.0.0.1"), 5000); } else { QByteArray block = "block"; tcpSocket->write(block); tcpSocket->flush(); } } catch(...){} QEventLoop eventloop; QTimer::singleShot(1000, &eventloop, SLOT(quit())); eventloop.exec(); } }
這樣收發(fā)就寫好了。
先說發(fā)包,這里是和上位機建立了長連接,我只需要知道上位機的IP和端口號即可建立連接,上位機不需要知道我的IP信息。如果上位機需要知道我的相關(guān)信息,可以在包中寫入,并根據(jù)實際需要調(diào)整發(fā)送頻率。這里有重連機制,上位機在一段時間沒有收到我發(fā)送的信息后,可以認(rèn)定我已經(jīng)離線。
再說收包,其實就是不斷地讀入緩沖區(qū)的內(nèi)容,緩沖區(qū)的大小和解析方式需要和上位機協(xié)調(diào),盡量在包過大時進(jìn)行拆包發(fā)送,下位機再根據(jù)解包信息判斷是否需要接包,以及信息是否齊全、有沒有丟包等。
收發(fā)框架搭好以后,就可以建立一定的收發(fā)規(guī)范進(jìn)行遠(yuǎn)程控制了,發(fā)包比較靈活,這里只說收包。
比如設(shè)定這樣的規(guī)則:上位機發(fā)送的所有的報文都有一段報文頭,記錄報文的總長度。報文頭部后面接一段自定義的操作類型,用來進(jìn)行指令分類。操作類型后接實際的操作指令。
代碼如下。
try{ //收包 //將接收內(nèi)容存儲到字符串中 char recvMsg[1024] = {'\0'}; int recvRe = tcpSocket->read(recvMsg, 1024); if(recvRe != 0 && recvRe != -1) //0:連接未發(fā)信息;-1:未連接 { QString recvMessage = recvMsg; //字符串解析 head = recvMessage.mid(0, HEAD_LENGTH).simplified(); //網(wǎng)絡(luò)頭,報文總長度 type = recvMessage.mid(HEAD_LENGTH, TYPE_LENGTH).simplified(); //請求類型 message = recvMessage.mid(HEAD_LENGTH + TYPE_LENGTH, recvMessage.length()).simplified(); //實際請求內(nèi)容 //按照字符串要求分類處理 handle(type, message); } } catch(...){}
預(yù)先定好報文頭部和指令類型的長度,就可以在收到包后按照位置對字符串進(jìn)行解析。分離出請求類型和請求內(nèi)容后,對指令進(jìn)行處理即可。同時也需要定義一定的上位機指令發(fā)送規(guī)范。
處理示例:
void handle(QString type, QString message) { QStringList handleOptions; handleOptions << "aaaa" << "bbbb" << "cccc" ; /* aaaa = 0 bbbb = 1 cccc = 2 */ switch (handleOptions.indexOf(type)) { case 0: break; case 1: break; case 2: break; default: qDebug() << "do not understand!"; break; } }
到此這篇關(guān)于Qt開發(fā)之使用socket實現(xiàn)遠(yuǎn)程控制的文章就介紹到這了,更多相關(guān)Qt socket遠(yuǎn)程控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言使用單鏈表實現(xiàn)學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言使用單鏈表實現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解
這篇文章主要介紹了C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09Objective-C中常用的結(jié)構(gòu)體NSRange,NSPoint,NSSize(CGSize),NSRect實例分析
這篇文章主要介紹了Objective-C中常用的結(jié)構(gòu)體NSRange,NSPoint,NSSize(CGSize),NSRect實例分析,有助于更加直觀的理解Object-C常用的結(jié)構(gòu)體,需要的朋友可以參考下2014-07-07C++11 模板參數(shù)的“右值引用”是轉(zhuǎn)發(fā)引用嗎
這篇文章主要介紹了C++11 模板參數(shù)的“右值引用”是轉(zhuǎn)發(fā)引用嗎,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05