Qt开源作品37-网络中转服务器
时间:2022-07-22
本文章向大家介绍Qt开源作品37-网络中转服务器,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、前言
用Qt做开发10年了,其中做过好多项目,基于现在web和移动互联网发展如此迅猛,大量的应用场景需要一个网络中转服务器,可以实现手机app或者其他客户端远程回控设备,现在物联网发展非常迅猛,这个将来也是大势所趋,所以有这个想法很久了,打算用Qt也来做个简单的网络中转服务器。
需求场景:
- 手机端或者其他端可以对设备进行回控,并查看设备各种运行状态,接收报警推送等。
- 同时支持在局域网、广域网、互联网访问,尤其是互联网访问。
- 权限控制,给定账号控制授权的设备,并自动拉取设备信息。
- 设备不在线要给出反馈信息提示以便分析。
- 每个连接都有自己的唯一编号作为标识符。
- 可以方便的拓展为微信接入+小程序接入+web接入。
二、代码思路
#include "tcpserver1.h"
#include "quiwidget.h"
TcpClient1::TcpClient1(QObject *parent) : QTcpSocket(parent)
{
ip = "127.0.0.1";
port = 6907;
deviceID = "SSJC00000001";
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(deleteLater()));
connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater()));
connect(this, SIGNAL(readyRead()), this, SLOT(readData()));
}
void TcpClient1::setIP(const QString &ip)
{
this->ip = ip;
}
QString TcpClient1::getIP() const
{
return this->ip;
}
void TcpClient1::setPort(int port)
{
this->port = port;
}
int TcpClient1::getPort() const
{
return this->port;
}
QString TcpClient1::getDeviceID()
{
return this->deviceID;
}
void TcpClient1::readData()
{
QByteArray data = this->readAll();
if (data.length() <= 0) {
return;
}
//取出唯一标识符,并过滤,可自行更改过滤条件
QByteArray cmd = data.mid(App::CmdStart1, App::CmdLen1);
QString id = QString(cmd);
if (id.startsWith("S") && deviceID != id) {
deviceID = id;
//发送信号更新标识符
emit receiveDeviceID(ip, port, deviceID);
}
QString buffer;
if (App::HexData1) {
buffer = QUIHelper::byteArrayToHexStr(data);
} else {
buffer = QString(data);
}
emit receiveData(ip, port, deviceID, buffer);
}
void TcpClient1::sendData(const QString &data)
{
QByteArray buffer;
if (App::HexData1) {
buffer = QUIHelper::hexStrToByteArray(data);
} else {
buffer = data.toLatin1();
}
this->write(buffer);
emit sendData(ip, port, deviceID, data);
}
TcpServer1::TcpServer1(QObject *parent) : QTcpServer(parent)
{
}
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
void TcpServer1::incomingConnection(qintptr handle)
#else
void TcpServer1::incomingConnection(int handle)
#endif
{
TcpClient1 *client = new TcpClient1(this);
client->setSocketDescriptor(handle);
connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(client, SIGNAL(sendData(QString, int, QString, QString)), this, SIGNAL(sendData(QString, int, QString, QString)));
connect(client, SIGNAL(receiveData(QString, int, QString, QString)), this, SIGNAL(receiveData(QString, int, QString, QString)));
connect(client, SIGNAL(receiveDeviceID(QString, int, QString)), this, SIGNAL(receiveDeviceID(QString, int, QString)));
QString ip = client->peerAddress().toString();
int port = client->peerPort();
QString deviceID = client->getDeviceID();
client->setIP(ip);
client->setPort(port);
emit clientConnected(ip, port, deviceID);
emit sendData(ip, port, deviceID, "客户端上线");
//追加到链表中
clients.append(client);
}
void TcpServer1::disconnected()
{
TcpClient1 *client = (TcpClient1 *)sender();
QString ip = client->getIP();
int port = client->getPort();
QString deviceID = client->getDeviceID();
emit clientDisconnected(ip, port, deviceID);
emit sendData(ip, port, deviceID, "客户端下线");
//断开连接后从链表中移除
clients.removeOne(client);
}
bool TcpServer1::start()
{
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
bool ok = listen(QHostAddress::AnyIPv4, App::ListenPort1);
#else
bool ok = listen(QHostAddress::Any, App::ListenPort1);
#endif
return ok;
}
void TcpServer1::stop()
{
foreach (TcpClient1 *client, clients) {
client->disconnectFromHost();
}
this->close();
}
bool TcpServer1::writeData(const QString &deviceID, const QString &data)
{
bool ok = false;
foreach (TcpClient1 *client, clients) {
if (client->getDeviceID() == deviceID) {
client->sendData(data);
ok = true;
}
}
return ok;
}
三、效果图
四、开源主页
以上作品完整源码下载都在开源主页,会持续不断更新作品数量和质量,欢迎各位关注。
- 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
- 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
- 个人主页:https://blog.csdn.net/feiyangqingyun
- 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
- MVC 控制器中传递dynamic(对象) 给视图
- 使用copy命令解决LONG类型的困扰(r2第24天)
- MVC 获取路由的 URL 参数值和默认值的集合。
- 用libsvm进行回归预测
- mvc路由配置.html结尾的伪静态
- 【编程基础】Java的接口和抽象类
- 循序渐进调优union相关的sql(r2笔记23天)
- 对分区表导入导出的水平,垂直切分(r2第22天)
- 巧用parallel极速提升数据加载速度(r2第21天)
- 【Windows编程】创建多文档界面
- 生产环境sqlldr加载性能问题及分析之二(r2第20天)
- [Python]从豆瓣批量获取看过电影的用户列表,并应用kNN算法预测用户性别
- 关于desc的一个奇怪问题及分析(r2第18天)
- R语言进行中文分词,并对6W条微博聚类
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PAT (Basic Level) Practice (中文)1002 写出这个数
- PAT (Basic Level) Practice (中文)1004 成绩排名
- PAT (Basic Level) Practice (中文)1006 换个格式输出整数
- PAT (Basic Level) Practice (中文)1008 数组元素循环右移问题
- Ceph分布式存储日常运维管理手册
- MyBatis为了解决二级缓存脏读问题,究竟做了那些骚操作!
- PAT (Basic Level) Practice (中文)1009 说反话
- PAT (Basic Level) Practice (中文)1011 A+B 和 C
- PAT (Basic Level) Practice (中文)1013 数素数
- PAT (Basic Level) Practice (中文)1012 数字分类
- PAT (Basic Level) Practice (中文)1016 部分A+B
- PAT (Basic Level) Practice (中文)1086 就不告诉你
- PAT (Basic Level) Practice (中文)1061 判断题
- 使用IDEA写Python之pytest环境搭建及第一个程序编写
- PAT (Basic Level) Practice (中文)1026 程序运行时间