个人网站 如何备案,左侧导航栏网站,山东定制网页建站,wordpress备案号不显示前言 首先看网络编程的定义#xff1a;两个不同主机设备之间的进程通信。C/S(Client-Server)是早期非常典型的软件架构#xff0c;C/S架构虽然简单#xff0c;但却非常适用于桌面图形化的QT项目。 本篇的QT项目是从真实的项目中简化出来#xff0c;满足很多相似的场景…前言 首先看网络编程的定义两个不同主机设备之间的进程通信。C/S(Client-Server)是早期非常典型的软件架构C/S架构虽然简单但却非常适用于桌面图形化的QT项目。 本篇的QT项目是从真实的项目中简化出来满足很多相似的场景创建一个TCP服务接收到消息后通过多线程执行后台CMD命令行并且自动把程序放到系统自启动目录中。 覆盖到QT的知识点任务栏托盘、右键菜单、TCP服务、多线程。
功能讲解
1、创建系统托盘
// 创建托盘图标QSystemTrayIcon *trayIcon new QSystemTrayIcon();trayIcon-setIcon(QIcon(:/index/img/default.png)); // 设置托盘图标
// 创建上下文菜单QMenu *menu new QMenu();
// 添加菜单项menu-addAction(exitAction);trayIcon-setContextMenu(menu);// 显示托盘图标trayIcon-show();
2、托盘右键菜单
// 创建上下文菜单QMenu *menu new QMenu();QAction *showAction new QAction(执行后台命令, app);//测试用// 连接信号与槽QObject::connect(showAction, QAction::triggered, []() {//测试打开谷歌浏览器QString cmd C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe;cmdrun act;act.Run(cmd);});QAction *exitAction new QAction(退出, app);QObject::connect(exitAction, QAction::triggered, app, QApplication::quit);// 添加菜单项menu-addAction(showAction);menu-addAction(exitAction);trayIcon-setContextMenu(menu);
showAction事件只是用来测试点击右键之后执行本地的CMD命令是否正常适合用来调用第三方软件达到指定的目的比如通过window的powershell脚本获取指定EXE执行程序的图标调通之后就可以注释掉用TCP创建的服务执行本地的CMD命令。
3、TCP服务
首先需要在.pro文件中加上network编译时才不会报错
QT core gui network
tcp服务头文件
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include QTcpServer
#include QTcpSocket
#include QDebug
#include QObject//请求包结构
typedef struct netPackQ
{char opCode[2];//暗号校验头--校验不对的直接丢弃char keyword[254];//交互的核心内容netPackQ(){memset(opCode,0,2);memset(keyword,0,254);}
} netPackQ;class Mytcpserver: public QObject {Q_OBJECTpublic:Mytcpserver(QObject *parent nullptr);private slots:void onNewConnection();private:QTcpServer *server;
};#endif // MYTCPSERVER_HTCP主文件
#include mytcpserver.h
#include cmdrun.hMytcpserver::Mytcpserver(QObject *parent) : QObject(parent) {// 创建 TCP 服务器server new QTcpServer(this);// 连接新连接信号到槽函数connect(server, QTcpServer::newConnection, this, Mytcpserver::onNewConnection);// 绑定到 10086 端口if (!server-listen(QHostAddress::Any, 10086)) {qDebug() Server could not start!;} else {qDebug() Server started on port 10086.;}
}void Mytcpserver::onNewConnection() {QTcpSocket *socket server-nextPendingConnection();// 连接读取数据信号connect(socket, QTcpSocket::readyRead, [socket]() {netPackQ packet;qint64 bytesReceived socket-read(reinterpret_castchar*(packet), sizeof(netPackQ));if (bytesReceived sizeof(netPackQ)) {// 处理接收到的数据qDebug() Received date;if(packet.opCode[0] 0x01 packet.opCode[1]9){//执行后台命令打开指定应用。比如C:\Windows\notepad.exeqDebug() Received keyword: packet.keyword;cmdrun act;act.Run(packet.keyword);//处理核心内容}socket-write(Received sucess\n); // 回复客户端} else {qDebug() Received incomplete data;}});// 连接断开信号connect(socket, QTcpSocket::disconnected, socket, QTcpSocket::deleteLater);
}4、多线程执行后台CMD命令
直接用进程执行CMD命令会导致托盘卡顿所以得用多线程来执行cmdrun类很简单如下
//头文件cmdrun.h
#ifndef CMDRUN_H
#define CMDRUN_H
#includeQString
#include threadCmd.h
class cmdrun
{
public:cmdrun();~cmdrun();int Run(QString cmd);
};#endif // CMDRUN_H//cpp文件:cmdrun.cpp
#include cmdrun.h
#include QDebugcmdrun::cmdrun()
{}cmdrun::~cmdrun()
{}int cmdrun::Run(QString cmd){//qDebug() __LINE__ cmd;ThreadCmd *thread new ThreadCmd(cmd);thread-start();return 1;
}5、多进程执行CMD命令
//头文件:threadCmd.h
#ifndef THREADCMD_H
#define THREADCMD_H#include QThread
#include QStringclass ThreadCmd : public QThread
{Q_OBJECT
public:explicit ThreadCmd(const QString param) ;protected:void run() override;private:QString m_param;
};#endif // THREADCMD_H//cpp文件:threadCmd.cpp
#ifndef THREADCMD_CPP
#define THREADCMD_CPP#include threadCmd.h
#include QDebug
#include QProcess
#include QTextCodecThreadCmd::ThreadCmd(const QString param) : m_param(param) {}void ThreadCmd::run(){QProcess process;// 执行命令QString cmd D:\\cmdexec.cmd \ m_param \;//QString cmd m_param;//qDebug() __LINE__ cmd;// 启动快捷方式if (QProcess::startDetached(cmd)) {qDebug() Application launched successfully.;} else {qDebug() Failed to launch application.;}// 进程使用完毕后可以手动删除process.deleteLater();
}#endif // THREADCMD_CPP6、开机自启动
系统托盘通常都有开机自启动的需求可以手动拷贝到启动目录或者在程序中编写把应用程序的.lnk文件放到自启动目录中
void addToStartup(const QString appPath) {QString startupPath QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) /Startup/;//qDebug() __LINE__ startupPath;// 创建启动文件夹如果不存在QDir dir(startupPath);if (!dir.exists()) {dir.mkpath(.);}// 创建快捷方式Windows 特有QString shortcutPath startupPath cstsvr.lnk;if (!QFile::exists(shortcutPath)) {// 使用 PowerShell 创建快捷方式 (请根据实际情况调整)QString command QString(powershell -command \$ws New-Object -ComObject WScript.Shell; $s $ws.CreateShortcut(%1); $s.TargetPath%2; $s.Save()\).arg(shortcutPath).arg(appPath);QProcess::execute(command);}
}int main(int argc, char *argv[]) {QApplication app(argc, argv);// 获取当前应用程序的完整路径QString appPath QCoreApplication::applicationFilePath();//qDebug() __LINE__ appPath;addToStartup(appPath);// 添加自启动到启动文件夹.......
}
篇尾 不同主机之间的进程间通信通常需要设定一端为服务端进行侦听当然也可以两端都设置为服务端服务端≠服务器服务端只代表某项服务的侦听端比如本篇涉及的项目需求是国产Linux系统需要获取window系统的所有应用程序的图标并且取回到国产Linux系统的QT界面中展示此时就需要在window系统上挂着【根据exe应用路径获取图片】的服务端并把文件回传给Linux。