[add]添加远程平台数据同步服务

This commit is contained in:
liang-ys 2026-03-24 17:22:54 +08:00
parent 65f83b476d
commit a8cb3c3b1f
7 changed files with 948 additions and 1 deletions

View File

@ -8,7 +8,8 @@ SUBDIRS += \
sys_file_sync \
sys_startup \
sys_svn_file_sync_api \
sys_svn_file_sync
sys_svn_file_sync \
sys_data_sync_server
sys_file_sync.depends = sys_file_sync_api
sys_svn_file_sync.depends = sys_svn_file_sync_api

View File

@ -0,0 +1,742 @@
#include "datasyncserver.h"
DataSyncServer::DataSyncServer(QObject *parent) : QTcpServer(parent)
{
}
/**
* @brief
* @param handle socket描述符
*
* QTcpSocket对象
*/
void DataSyncServer::incomingConnection(qintptr handle)
{
QTcpSocket *socket = new QTcpSocket(this);
socket->setSocketDescriptor(handle);
requestBuffers[socket] = QByteArray();
connect(socket, &QTcpSocket::readyRead, this, &DataSyncServer::onSocketReadyRead);
connect(socket, &QTcpSocket::disconnected, this, &DataSyncServer::onSocketDisconnected);
connect(socket, &QTcpSocket::bytesWritten, this, &DataSyncServer::onSocketBytesWritten);
}
/**
* @brief Socket数据就绪槽函数
*
* HTTP请求
* 50MB
*/
void DataSyncServer::onSocketReadyRead()
{
QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
if (!socket || socket->state() != QAbstractSocket::ConnectedState) return;
requestBuffers[socket].append(socket->readAll());
QString method;
QString path;
QByteArray body;
int contentLength = -1;
//尝试解析HTTP请求
if (!parseHttpRequest(requestBuffers[socket], method, path, body, contentLength)) {
//请求尚未完整接收,等待更多数据
if (requestBuffers[socket].size() > 1024 * 1024 *50) { //限制最大请求大小为50MB
qDebug()<<"请求过大,关闭连接";
sendErrorResponse(socket, 413, "请求实体body过大最大限制为50M");
socket->disconnectFromHost();
//清理缓冲区
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
return;
}
//请求解析成功,处理请求(注意:此时不清除缓冲区,因为可能需要异步处理)
handleRequest(socket);
}
/**
* @brief Socket数据写入完成槽函数
* @param bytes
*
*
*/
void DataSyncServer::onSocketBytesWritten(qint64 bytes)
{
//可以在这里添加写入完成的回调处理,目前为空实现
Q_UNUSED(bytes);
}
/**
* @brief Socket断开连接槽函数
*
* Socket相关的所有数据
*/
void DataSyncServer::onSocketDisconnected()
{
QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
if (!socket) return;
//清理该 socket 的所有相关数据
requestBuffers.remove(socket);
socketTempFiles.remove(socket);
socketOperationType.remove(socket);
socket->deleteLater();
}
/**
* @brief HTTP请求
* @param data HTTP请求数据
* @param method HTTP方法
* @param path
* @param body
* @param contentLength Content-Length值
* @return truefalse
*
* HTTP请求行Content-Length判断body是否完整
*/
bool DataSyncServer::parseHttpRequest(const QByteArray &data, QString &method, QString &path, QByteArray &body, int &contentLength)
{
//查找请求头和请求体的分隔符
int headerEnd = data.indexOf("\r\n\r\n");
if (headerEnd < 0) {
return false; //头部尚未完整接收
}
//解析请求头
QByteArray headerData = data.left(headerEnd);
QList<QByteArray> headerLines = headerData.split('\n');
if (headerLines.isEmpty()) {
return false;
}
//解析请求行;格式为"METHOD /path HTTP/1.x"
QByteArray requestLine = headerLines[0].trimmed();
QList<QByteArray> requestParts = requestLine.split(' ');
if (requestParts.size() < 2) {
return false;
}
method = QString::fromLatin1(requestParts[0]);
path = QString::fromLatin1(requestParts[1]);
//提取查询数据(如果有)
int queryIndex = path.indexOf('?');
if (queryIndex >= 0) {
path = path.left(queryIndex);
}
//查找 Content-Length
contentLength = -1;
for (int i = 1; i < headerLines.size(); ++i) {
QByteArray line = headerLines[i].trimmed();
if (QString(line).startsWith("Content-Length:", Qt::CaseInsensitive)) {
bool ok;
contentLength = line.mid(15).trimmed().toInt(&ok);
if (!ok) contentLength = -1;
break;
}
}
//提取请求体
int bodyStart = headerEnd + 4;
QByteArray receivedBody = data.mid(bodyStart);
if (method.toUpper() == "POST" || method.toUpper() == "PUT") {
if (contentLength > 0) {
//需要接收完整的body
if (receivedBody.size() < contentLength) {
return false; //body 尚未完整接收
}
body = receivedBody.left(contentLength);
}
else {
// 没有Content-Length 假设所有剩余数据都是body
body = receivedBody;
}
}
return true;
}
/**
* @brief HTTP请求
* @param socket socket指针
*
* HTTP请求并根据方法和路径分发到相应的处理函数
*
* - GET /backup ->
* - POST /restore ->
* - -> 404
*/
void DataSyncServer::handleRequest(QTcpSocket *socket)
{
QByteArray fullRequest = requestBuffers[socket];
QString method;
QString path;
QByteArray body;
int contentLength = -1;
if (!parseHttpRequest(fullRequest, method, path, body, contentLength)) {
sendErrorResponse(socket, 400, "错误请求!");
socket->disconnectFromHost();
return;
}
qDebug()<<"收到请求:"<<method<<path;
//处理不同的路径
if (method.toUpper() == "GET" && path == "/backup") {
socketOperationType[socket] = true; //标记为备份操作
handleBackup(socket);
}
else if (method.toUpper() == "POST" && path == "/restore") {
socketOperationType[socket] = false; //标记为恢复操作
handleRestore(socket, body);
}
else {
sendErrorResponse(socket, 404, "Not Found");
socket->disconnectFromHost();
// 请求处理完成,清理缓冲区
requestBuffers.remove(socket);
socketOperationType.remove(socket);
}
}
/**
* @brief
* @param socket socket指针
*
*
* 1.
* 2.
* 3. 使tar命令异步打包data目录
* 4. onTarProcessFinished中发送文件给客户端
*/
void DataSyncServer::handleBackup(QTcpSocket *socket)
{
//检查socket是否仍然连接
if (!socket || socket->state() != QAbstractSocket::ConnectedState) {
qDebug() << "Socket已断开取消备份操作";
if (socket) {
requestBuffers.remove(socket);
socketOperationType.remove(socket);
}
return;
}
//确保目录存在
QString appDir = QCoreApplication::applicationDirPath() + "/../..";
QString tmpDir = QDir(appDir).filePath("tmp");
QString dataDir = QDir(appDir).filePath("data");
if (!ensureDirectoryExists(tmpDir)) {
qDebug() << "无法创建临时目录:" << tmpDir;
sendErrorResponse(socket, 500, "无法创建临时目录tmp");
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
//检查数据目录是否存在
if (!QDir(dataDir).exists()) {
qDebug() << "数据目录不存在:" << dataDir;
sendErrorResponse(socket, 500, "data目录不存在");
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
//生成唯一的临时文件名,避免并发冲突
QString uniqueId = QUuid::createUuid().toString().remove('{').remove('}');
QString outputFile = tmpDir + QDir::separator() + "data_" + uniqueId + ".zip";
// 使用QProcess 异步执行tar命令避免阻塞
QProcess *process = new QProcess(this);
processSockets[process] = socket;
// 设置tar命令参数使用setProgram/setArguments避免路径问题
process->setProgram("zip");
process->setWorkingDirectory(appDir);
QStringList arguments;
arguments << "-r" << outputFile << "data";
process->setArguments(arguments);
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &DataSyncServer::onTarProcessFinished);
connect(process, &QProcess::errorOccurred, this, &DataSyncServer::onTarProcessError);
qDebug()<< "start backup command:tar" << arguments.join(" ");
// 保存输出文件路径,供后续使用
socketTempFiles[socket] = outputFile;
process->start();
if (!process->waitForStarted(3000)) {
qDebug() << "tar 进程启动失败:" << process->errorString();
sendErrorResponse(socket, 500, "无法启动tar进程");
processSockets.remove(process);
socketTempFiles.remove(socket);
process->deleteLater();
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
}
/**
* @brief
* @param socket socket指针
* @param body HTTP请求体tar文件数据
*
*
* 1.
* 2. tar数据保存到临时文件
* 3. data目录
* 4. 使tar命令异步解包到data目录
* 5.
*/
void DataSyncServer::handleRestore(QTcpSocket *socket, const QByteArray &body)
{
// 检查socket是否仍然连接
if (!socket || socket->state() != QAbstractSocket::ConnectedState) {
qDebug() << "Socket已断开取消恢复操作";
if (socket) {
requestBuffers.remove(socket);
socketOperationType.remove(socket);
}
return;
}
if (body.isEmpty()) {
qDebug() << "恢复请求的 body 为空";
sendErrorResponse(socket, 400, "错误请求请求实体body为空");
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
//确保目录存在
QString appDir = QCoreApplication::applicationDirPath() + "/../..";
QString tmpDir = QDir(appDir).filePath("tmp");
QString restoreDir = QDir(appDir).filePath("data");
if (!ensureDirectoryExists(tmpDir)) {
qDebug() << "无法创建临时目录:" << tmpDir;
sendErrorResponse(socket, 500, "无法创建临时目录tmp");
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
//生成唯一的临时文件名,避免并发冲突
QString uniqueId = QUuid::createUuid().toString().remove('{').remove('}');
QString saveFile = tmpDir + QDir::separator() + "data_" + uniqueId + ".tar";
//保存上传的文件
QFile file(saveFile);
if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "无法创建临时文件:" << saveFile << file.errorString();
sendErrorResponse(socket, 500, "无法创建临时文件!");
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
qint64 written = file.write(body);
file.close();
if (written != body.size()) {
qDebug() << "文件写入不完整,期望:" << body.size() << "实际:" <<written;
sendErrorResponse(socket, 500, "临时文件写入失败!");
//清理不完整的临时文件
if (QFile::exists(saveFile)) {
QFile::remove(saveFile);
}
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
qDebug() << "已保存上传文件:" << saveFile << "大小:" << written;
// 删除旧目录(如果存在)
if (QDir(restoreDir).exists()) {
qDebug() << "删除旧目录:" << restoreDir;
if (!QDir(restoreDir).removeRecursively()) {
qDebug() << "警告:无法完全删除旧目录:" << restoreDir;
}
}
QProcess *process = new QProcess(this);
processSockets[process] = socket;
process->setProgram("tar");
QStringList arguments;
arguments << "xf" << saveFile << "-C" << appDir;
process->setArguments(arguments);
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &DataSyncServer::onTarProcessFinished);
connect(process, &QProcess::errorOccurred, this, &DataSyncServer::onTarProcessError);
qDebug() << "开始执行恢复命令tar" << arguments.join(" ");
//保存临时文件路径,成功后删除
socketTempFiles[socket] = saveFile;
process->start();
if (!process->waitForStarted(3000)) {
qDebug() << "tar 进程启动失败:" << process->errorString();
sendErrorResponse(socket, 500, "无法启动tar进程");
processSockets.remove(process);
socketTempFiles.remove(socket);
//清理临时文件
if (QFile::exists(saveFile)) {
QFile::remove(saveFile);
}
process->deleteLater();
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
return;
}
}
/**
* @brief tar进程完成槽函数
* @param exitCode 退0
* @param exitStatus 退NormalExit表示正常退出
*
* tar命令执行完成时调用
* -
* - tar文件并发送给客户端
* -
*/
void DataSyncServer::onTarProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
QProcess *process = qobject_cast<QProcess*>(sender());
if (!process) return;
QTcpSocket *socket = processSockets.value(process);
if (!socket) {
process->deleteLater();
return;
}
// 检查socket是否仍然连接
if (socket->state() != QAbstractSocket::ConnectedState) {
qDebug() << "Socket已断开清理资源";
QString tempFile = socketTempFiles.value(socket);
if (!tempFile.isEmpty() && QFile::exists(tempFile)) {
QFile::remove(tempFile);
}
processSockets.remove(process);
socketTempFiles.remove(socket);
requestBuffers.remove(socket);
socketOperationType.remove(socket);
process->deleteLater();
return;
}
processSockets.remove(process);
QString tempFile = socketTempFiles.value(socket);
bool isBackup = socketOperationType.value(socket, false);
if (exitStatus != QProcess::NormalExit || exitCode != 0) {
QByteArray errorOutput = process->readAllStandardError();
qDebug() << "tar 命令执行失败,退出码:" << exitCode << "错误:" << errorOutput;
sendErrorResponse(socket, 500, "tar进程执行失败");
//清理临时文件
if (!tempFile.isEmpty() && QFile::exists(tempFile)) {
QFile::remove(tempFile);
}
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
socketTempFiles.remove(socket);
process->deleteLater();
return;
}
// tar 命令执行成功
QByteArray standardOutput = process->readAllStandardOutput();
QByteArray errorOutput = process->readAllStandardError();
if (!standardOutput.isEmpty()) {
qDebug() << "tar 标准输出:" << standardOutput;
}
if (!errorOutput.isEmpty()) {
qDebug() << "tar 标准错误:" << errorOutput;
}
//根据操作类型处理
if (isBackup && !tempFile.isEmpty() && QFile::exists(tempFile)) {
//备份操作;分块发送文件,避免大文件占用过多内存
QFile file(tempFile);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "无法打开备份文件:" << tempFile;
sendErrorResponse(socket, 500, "无法打开临时文件!");
QFile::remove(tempFile);
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
socketTempFiles.remove(socket);
process->deleteLater();
return;
}
qint64 fileSize = file.size();
if (fileSize == 0) {
qDebug() << "备份文件为空";
sendErrorResponse(socket, 500, "临时文件为空!");
file.close();
QFile::remove(tempFile);
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
socketTempFiles.remove(socket);
process->deleteLater();
return;
}
qDebug() << "send backup file,size:" << fileSize;
// 发送HTTP响应头
QByteArray header = "HTTP/1.1 200 OK\r\n";
header += "Content-Type: application/octet-stream\r\n";
header += "Content-Length: " + QByteArray::number(fileSize) + "\r\n";
header += "Connection: close\r\n";
header += "Date: " + QDateTime::currentDateTimeUtc().toString("ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1() + "\r\n";
header += "Server: DataSyncServer/1.0\r\n";
header += "\r\n";
socket->write(header);
// 分块读取并发送文件
const qint64 chunkSize = 64 * 1024; // 64KB 块
while (!file.atEnd()) {
QByteArray chunk = file.read(chunkSize);
if (chunk.isEmpty() && !file.atEnd()) {
qDebug() << "文件读取错误";
file.close();
QFile::remove(tempFile);
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
socketTempFiles.remove(socket);
process->deleteLater();
return;
}
socket->write(chunk);
socket->waitForBytesWritten(30000);
}
file.close();
// 清理临时文件
QFile::remove(tempFile);
}
else {
// 恢复操作成功
qDebug() << "恢复操作成功完成";
sendSuccessResponse(socket, QByteArray("文件接收并解压成功!"), "text/plain; charset=utf-8");
// 清理临时文件
if (!tempFile.isEmpty() && QFile::exists(tempFile)) {
QFile::remove(tempFile);
}
}
socket->disconnectFromHost();
requestBuffers.remove(socket);
socketOperationType.remove(socket);
socketTempFiles.remove(socket);
process->deleteLater();
}
/**
* @brief tar进程错误槽函数
* @param error
*
* tar命令执行出错时被调用
*
*/
void DataSyncServer::onTarProcessError(QProcess::ProcessError error)
{
QProcess *process = qobject_cast<QProcess*>(sender());
if (!process) return;
QTcpSocket *socket = processSockets.value(process);
if (!socket) {
process->deleteLater();
return;
}
QString errorString;
switch (error) {
case QProcess::FailedToStart:
errorString = "tar command failed to start";
break;
case QProcess::Crashed:
errorString = "tar command crashed";
break;
case QProcess::Timedout:
errorString = "tar command timed out";
break;
case QProcess::WriteError:
errorString = "tar command write error";
break;
case QProcess::ReadError:
errorString = "tar command read error";
break;
default:
errorString = "tar command unknown error";
break;
}
qDebug() << "tar 进程错误:" << errorString;
QString tempFile = socketTempFiles.value(socket);
// 清理临时文件
if (!tempFile.isEmpty() && QFile::exists(tempFile)) {
QFile::remove(tempFile);
}
if (socket && socket->state() == QAbstractSocket::ConnectedState) {
sendErrorResponse(socket, 500, errorString.toLatin1());
socket->disconnectFromHost();
}
requestBuffers.remove(socket);
socketOperationType.remove(socket);
process->deleteLater();
}
/**
* @brief HTTP错误响应
* @param socket socket指针
* @param statusCode HTTP状态码400404413500
* @param message
*
* HTTP错误响应
* Data和Server等标准HTTP响应头字段
*/
void DataSyncServer::sendErrorResponse(QTcpSocket *socket, int statusCode, const QByteArray &message)
{
if (!socket || socket->state() != QAbstractSocket::ConnectedState) {
return;
}
QByteArray response = "HTTP/1.1 " + QByteArray::number(statusCode) + " ";
switch (statusCode) {
case 400: response += "Bad Request"; break;
case 404: response += "Not Found"; break;
case 413: response += "Request Entity Too Large"; break;
case 500: response += "Internal Server Error"; break;
default: response += "Error"; break;
}
response += "\r\n";
response += "Content-Type: text/plain; charset=utf-8\r\n";
response += "Content-Length: " + QByteArray::number(message.size()) + "\r\n";
response += "Connection: close\r\n";
response += "Date: " + QDateTime::currentDateTimeUtc().toString("ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1() + "\r\n";
response += "Server: DataSyncServer/1.0\r\n";
response += "\r\n";
response += message;
socket->write(response);
}
/**
* @brief HTTP成功响应
* @param socket socket指针
* @param content
* @param contentType Content-Type响应头"application/octet-stream"
*
* HTTP 200
* Data和Server等标准HTTP响应头字段
*/
void DataSyncServer::sendSuccessResponse(QTcpSocket *socket, const QByteArray &content, const QByteArray &contentType)
{
if (!socket || socket->state() != QAbstractSocket::ConnectedState) {
return;
}
QByteArray response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: " + contentType + "\r\n";
response += "Content-Length: " + QByteArray::number(content.size()) + "\r\n";
response += "Connection: close\r\n";
response += "Date: " + QDateTime::currentDateTimeUtc().toString("ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1() + "\r\n";
response += "Server: DataSyncServer/1.0\r\n";
response += "\r\n";
response += content;
socket->write(response);
}
/**
* @brief
* @param path
* @return truefalse
*
*
*/
bool DataSyncServer::ensureDirectoryExists(const QString &path)
{
QDir dir;
if (!dir.exists(path)) {
return dir.mkpath(path);
}
return true;
}
/**
* @brief
* @param path
* @return
*
*
* - ".."
* -
*
*
*/
QString DataSyncServer::sanitizePath(const QString &path)
{
// 移除潜在的路径遍历攻击(虽然在这个实现中可能不需要,但保留接口)
QString sanitized = path;
sanitized.replace("..", "");
QString sep = QDir::separator();
sanitized.replace(sep + sep, sep);
return sanitized;
}

View File

@ -0,0 +1,53 @@
#ifndef DATASYNCSERVER_H
#define DATASYNCSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QUuid>
#include <QDateTime>
class DataSyncServer : public QTcpServer
{
Q_OBJECT
public:
explicit DataSyncServer(QObject *parent = nullptr);
signals:
public slots:
protected:
void incomingConnection(qintptr handle);
private slots:
void onSocketReadyRead();
void onSocketBytesWritten(qint64 bytes);
void onSocketDisconnected();
void onTarProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onTarProcessError(QProcess::ProcessError error);
private:
// 为每个socket 维护请求缓冲区,处理分包问题
QHash<QTcpSocket*, QByteArray> requestBuffers;
QHash<QProcess*, QTcpSocket*> processSockets;
QHash<QTcpSocket*, QString> socketTempFiles;
//标记每个socket的操作类型true=备份false=恢复
QHash<QTcpSocket*, bool> socketOperationType;
bool parseHttpRequest(const QByteArray &data, QString &method, QString &path, QByteArray &body, int &contentLength);
void handleRequest(QTcpSocket *socket);
void handleBackup(QTcpSocket *socket);
void handleRestore(QTcpSocket *socket, const QByteArray &body);
void sendErrorResponse(QTcpSocket *socket, int statusCode, const QByteArray &message);
void sendSuccessResponse(QTcpSocket *socket, const QByteArray &content, const QByteArray &contentType);
bool ensureDirectoryExists(const QString &path);
QString sanitizePath(const QString &path);
};
#endif // DATASYNCSERVER_H

View File

@ -0,0 +1,17 @@
#include "datasyncserver.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
DataSyncServer data_sync_server;
if (!data_sync_server.listen(QHostAddress::Any, 8080)) {
qFatal("Listen failed");
}
qDebug("data_sync_server started at 8080");
return a.exec();
}

View File

@ -0,0 +1,41 @@
@echo off
setlocal
REM 固定用户名
set username=admin
echo 请输入远程主机IP地址
set /p ip=
if "%ip%"=="" (
echo IP地址不能为空
pause
exit
)
echo.
echo 请选择操作:
echo 1 - 启动系统
echo 2 - 停止系统
set /p choice=请输入 1 或 2
if "%choice%"=="1" (
set command=/opt/EnergyHub/platform/oe2203_aarch64_release/sys_ctrl
) else if "%choice%"=="2" (
set command=/opt/EnergyHub/platform/oe2203_aarch64_release/sys_ctrl -s
) else (
echo 无效选择!
pause
exit
)
echo.
echo 正在连接 %ip% ...
echo 如果需要密码,请根据提示输入。
echo.
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=NUL %username%@%ip% %command%
echo.
echo 执行完成。
pause

View File

@ -0,0 +1,40 @@
#!/bin/bash
# 固定用户名
username="admin"
echo "请输入远程主机IP地址"
read ip
if [ -z "$ip" ]; then
echo "IP地址不能为空"
read -p "按回车键退出..."
exit 1
fi
echo
echo "请选择操作:"
echo "1 - 启动系统"
echo "2 - 停止系统"
read -p "请输入 1 或 2" choice
if [ "$choice" = "1" ]; then
command="/opt/EnergyHub/platform/oe2203_aarch64_release/sys_ctrl"
elif [ "$choice" = "2" ]; then
command="/opt/EnergyHub/platform/oe2203_aarch64_release/sys_ctrl -s"
else
echo "无效选择!"
read -p "按回车键退出..."
exit 1
fi
echo
echo "正在连接 $ip ..."
echo "如果需要密码,请根据提示输入。"
echo
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${username}@${ip} "$command"
echo
echo "执行完成。"
read -p "按回车键退出..."

View File

@ -0,0 +1,53 @@
QT -= gui
QT += network
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp \
datasyncserver.cpp
HEADERS += \
datasyncserver.h
#-------------------------------------------------------------------
COMMON_PRI=$$PWD/../../common.pri
exists($$COMMON_PRI) {
include($$COMMON_PRI)
}else {
error("FATAL error: can not find common.pri")
}
# ------------------------------------------------------------------
# 脚本目录
SCRIPT_DIR = $$PWD/scripts
win32 {
SCRIPT_SRC = $$shell_path($$SCRIPT_DIR/remote_sys_ctrl.bat)
SCRIPT_DST = $$shell_path($$DESTDIR/remote_sys_ctrl.bat)
generate_script.commands = $$QMAKE_COPY "$$SCRIPT_SRC" "$$SCRIPT_DST"
}
unix:!macx { #Linux
SCRIPT_SRC = $$SCRIPT_DIR/remote_sys_ctrl.sh
SCRIPT_DST = $$DESTDIR/remote_sys_ctrl.sh
generate_script.commands = cp "$$SCRIPT_SRC" "$$SCRIPT_DST" && chmod +x "$$SCRIPT_DST"
}
QMAKE_EXTRA_TARGETS += generate_script
POST_TARGETDEPS += generate_script
# ------------------------------------------------------------------