網站首頁 編程語言 正文
Qt之使用socket實現遠程控制
在前面的文章中介紹過Qt心跳包的實現方法,本篇文章將會介紹下位機通過心跳包和上位機之間進行數據交互和遠程功能控制的實現方法。
首先介紹環境,下位機使用Qt作為主程序,上下位機使用TCP socket進行網絡通信,上位機實現方式任意。下位機心跳包線程在進程一開始就啟動,一直到進程結束才停止。
心跳包是一個始終獨立的線程,首先要搭建框架:
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(); //任務處理線程
~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{ //收包
//將接收內容存儲到字符串中
char recvMsg[1024] = {'\0'};
int recvRe = tcpSocket->read(recvMsg, 1024);
if(recvRe != 0 && recvRe != -1) //0:連接未發信息;-1:未連接
{
}
} catch(...){}
QEventLoop eventloop;
QTimer::singleShot(1, &eventloop, SLOT(quit()));
eventloop.exec();
}
});
while(true){
try{ //發包
//等待連接成功
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();
}
}
這樣收發就寫好了。
先說發包,這里是和上位機建立了長連接,我只需要知道上位機的IP和端口號即可建立連接,上位機不需要知道我的IP信息。如果上位機需要知道我的相關信息,可以在包中寫入,并根據實際需要調整發送頻率。這里有重連機制,上位機在一段時間沒有收到我發送的信息后,可以認定我已經離線。
再說收包,其實就是不斷地讀入緩沖區的內容,緩沖區的大小和解析方式需要和上位機協調,盡量在包過大時進行拆包發送,下位機再根據解包信息判斷是否需要接包,以及信息是否齊全、有沒有丟包等。
收發框架搭好以后,就可以建立一定的收發規范進行遠程控制了,發包比較靈活,這里只說收包。
比如設定這樣的規則:上位機發送的所有的報文都有一段報文頭,記錄報文的總長度。報文頭部后面接一段自定義的操作類型,用來進行指令分類。操作類型后接實際的操作指令。
代碼如下。
try{ //收包
//將接收內容存儲到字符串中
char recvMsg[1024] = {'\0'};
int recvRe = tcpSocket->read(recvMsg, 1024);
if(recvRe != 0 && recvRe != -1) //0:連接未發信息;-1:未連接
{
QString recvMessage = recvMsg;
//字符串解析
head = recvMessage.mid(0, HEAD_LENGTH).simplified(); //網絡頭,報文總長度
type = recvMessage.mid(HEAD_LENGTH, TYPE_LENGTH).simplified(); //請求類型
message = recvMessage.mid(HEAD_LENGTH + TYPE_LENGTH, recvMessage.length()).simplified(); //實際請求內容
//按照字符串要求分類處理
handle(type, message);
}
} catch(...){}
預先定好報文頭部和指令類型的長度,就可以在收到包后按照位置對字符串進行解析。分離出請求類型和請求內容后,對指令進行處理即可。同時也需要定義一定的上位機指令發送規范。
處理示例:
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;
}
}
原文鏈接:https://blog.csdn.net/m0_60259116/article/details/127926529
相關推薦
- 2022-04-16 C#算法之實現阿姆斯特朗數_C#教程
- 2022-09-06 Python進程管理神器Supervisor詳解_python
- 2022-06-20 深入淺析C#?11?對?ref?和?struct?的改進_C#教程
- 2023-01-29 HTTP與HTTPS超文本傳輸協議的區別是什么_經驗交流
- 2022-10-02 Flutter的鍵值存儲數據庫使用示例詳解_Android
- 2022-02-04 防止點擊量頁面刷新增加的簡單處理方法
- 2022-11-28 C#時間戳基本使用方法詳解_C#教程
- 2022-11-07 Python實現簡易凱撒密碼的示例代碼_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支