• 2943阅读
  • 5回复

Qt开源作品37-网络中转服务器 [复制链接]

上一主题 下一主题
离线liudianwu
 

图酷模式  只看楼主 倒序阅读 楼主  发表于: 2020-06-21

## 一、前言
用Qt做开发10年了,其中做过好多项目,基于现在web和移动互联网发展如此迅猛,大量的应用场景需要一个网络中转服务器,可以实现手机app或者其他客户端远程回控设备,现在物联网发展非常迅猛,这个将来也是大势所趋,所以有这个想法很久了,打算用Qt也来做个简单的网络中转服务器。

**需求场景:**

1. 手机端或者其他端可以对设备进行回控,并查看设备各种运行状态,接收报警推送等。
2. 同时支持在局域网、广域网、互联网访问,尤其是互联网访问。
3. 权限控制,给定账号控制授权的设备,并自动拉取设备信息。
4. 设备不在线要给出反馈信息提示以便分析。
5. 每个连接都有自己的唯一编号作为标识符。
6. 可以方便的拓展为微信接入+小程序接入+web接入。

## 二、代码思路
```c++
#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;
}
```

## 三、效果图



## 四、开源主页
**以上作品完整源码下载都在开源主页,会持续不断更新作品数量和质量,欢迎各位关注。**

1. 国内站点:[https://gitee.com/feiyangqingyun/QWidgetDemo](https://gitee.com/feiyangqingyun/QWidgetDemo)
2. 国际站点:[https://github.com/feiyangqingyun/QWidgetDemo](https://github.com/feiyangqingyun/QWidgetDemo)
3. 个人主页:[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
4. 知乎主页:[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
欢迎关注微信公众号:Qt实战/Qt入门和进阶(各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发) QQ:517216493  WX:feiyangqingyun  QQ群:751439350
离线jsxyhyj

只看该作者 1楼 发表于: 2020-06-24
接收是红色的,发送是绿色的,这个是怎么弄出来的?
离线clickto

只看该作者 2楼 发表于: 2020-06-24
使用html的<font>标签可以设置字体颜色。
离线圣域天子

只看该作者 3楼 发表于: 2020-06-25
什么叫中转服务器?就是代理吗?
离线mndsoft

只看该作者 4楼 发表于: 2020-08-06
  不好意思,新手,编译调试运行显示: [debug/main_res.o] Error 1  怎么解决呢? 谢谢
离线mndsoft

只看该作者 5楼 发表于: 2020-08-07
还有这个中转如何实现 一个 APP客户端 可以查询多个呢?也就是 多个设备转发 同一个APP
快速回复
限100 字节
 
上一个 下一个