From 0abbb46040d31c61540cf3d613503aa051703d00 Mon Sep 17 00:00:00 2001 From: Mentalflow <312902918@qq.com> Date: Sun, 11 Dec 2022 14:04:13 +0800 Subject: [PATCH] Initial commit --- DataManager.pro | 26 +++++++++ README.md | 2 +- datamanager.cpp | 7 +++ datamanager.h | 16 +++++ main.cpp | 13 +++++ protocol.cpp | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ protocol.h | 59 +++++++++++++++++++ tcpclient.cpp | 96 ++++++++++++++++++++++++++++++ tcpclient.h | 39 +++++++++++++ tcpserver.cpp | 121 ++++++++++++++++++++++++++++++++++++++ tcpserver.h | 36 ++++++++++++ 11 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 DataManager.pro create mode 100644 datamanager.cpp create mode 100644 datamanager.h create mode 100644 main.cpp create mode 100644 protocol.cpp create mode 100644 protocol.h create mode 100644 tcpclient.cpp create mode 100644 tcpclient.h create mode 100644 tcpserver.cpp create mode 100644 tcpserver.h diff --git a/DataManager.pro b/DataManager.pro new file mode 100644 index 0000000..1dfe003 --- /dev/null +++ b/DataManager.pro @@ -0,0 +1,26 @@ +QT -= gui +QT += network +CONFIG += c++11 console +CONFIG -= app_bundle + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + datamanager.cpp \ + main.cpp \ + protocol.cpp \ + tcpclient.cpp \ + tcpserver.cpp + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +HEADERS += \ + datamanager.h \ + protocol.h \ + tcpclient.h \ + tcpserver.h diff --git a/README.md b/README.md index e8e8e02..1d82135 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # data_manager -一个轻量级、可拓展的,基于Json的通信协议。 +一个轻量级、可拓展的,基于Json的通信协议(开发中)。 diff --git a/datamanager.cpp b/datamanager.cpp new file mode 100644 index 0000000..a048227 --- /dev/null +++ b/datamanager.cpp @@ -0,0 +1,7 @@ +#include "datamanager.h" + +DataManager::DataManager(QObject *parent) + : QObject{parent} +{ + +} diff --git a/datamanager.h b/datamanager.h new file mode 100644 index 0000000..483b391 --- /dev/null +++ b/datamanager.h @@ -0,0 +1,16 @@ +#ifndef DATAMANAGER_H +#define DATAMANAGER_H + +#include + +class DataManager : public QObject +{ + Q_OBJECT +public: + explicit DataManager(QObject *parent = nullptr); + +signals: + +}; + +#endif // DATAMANAGER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..44ee8e9 --- /dev/null +++ b/main.cpp @@ -0,0 +1,13 @@ +#include +#include "protocol.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + Protocol *p = Protocol::getInstance(); + QList users{QString("123321123"),QString("123321123"),QString("123321123"),QString("123321123")}; + qDebug()<data_parser(p->data_maker(Protocol::ONLINEUSERS,4,users)); + qDebug()<data_encrypt(p->data_maker(Protocol::ONLINEUSERS,4,users)); + qDebug()<data_decrypt(p->data_encrypt(p->data_maker(Protocol::ONLINEUSERS,4,users))); + return a.exec(); +} diff --git a/protocol.cpp b/protocol.cpp new file mode 100644 index 0000000..98db9b4 --- /dev/null +++ b/protocol.cpp @@ -0,0 +1,152 @@ +#include "protocol.h" +#include +#include + +Protocol Protocol::protocol_instance; +Protocol::Protocol(QObject *parent) + : QObject{parent} +{ + +} + +Protocol::~Protocol() +{ + +} + +Protocol* Protocol::getInstance() +{ + return &protocol_instance; +} + +QByteArray Protocol::data_builder(QList &args) +{ + QJsonObject data; + switch(args[0].get_data_types()) + { + case MESSAGE: + { + if (args.length()==2) + { + data.insert("type","message"); + data.insert("data",args[1].get_string()); + } + else if (args.length()==3) + { + data.insert("type","message"); + data.insert("to_user",args[1].get_string()); + data.insert("data",args[2].get_string()); + } + break; + } + case FILE: + { + data.insert("type","file"); + data.insert("name",args[1].get_string()); + data.insert("data",args[2].get_string()); + break; + } + case REQUEST: + { + data.insert("type","request"); + data.insert("action",args[1].get_string()); + QList content = args[2].get_list(); + QJsonObject json_content; + for (int i=0; i users = args[2].get_list(); + QJsonArray json_users; + for (auto &user:users) + json_users.append(user); + data.insert("users",json_users); + break; + } + case RESPONSE: + { + data.insert("type","response"); + data.insert("action",args[1].get_string()); + QList content = args[2].get_list(); + QJsonObject json_content; + for (int i=0; i Protocol::data_parser(QByteArray data) +{ + QJsonDocument json_data = QJsonDocument::fromJson(data); + if (json_data["type"] == "message") + return qMakePair(MESSAGE,json_data.object()); + else if (json_data["type"] == "file") + return qMakePair(FILE,json_data.object()); + else if (json_data["type"] == "request") + return qMakePair(REQUEST,json_data.object()); + else if (json_data["type"] == "online_users") + return qMakePair(ONLINEUSERS,json_data.object()); + else if (json_data["type"] == "response") + return qMakePair(RESPONSE,json_data.object()); + else + return qMakePair(RESPONSE,json_data.object()); +} + +QByteArray Protocol::XOR_En_Decrypt(QString src) +{ + QByteArray result; + for(auto &i:src) + result.append(i.toLatin1() ^ cipher_word); + return result; +} + +QByteArray Protocol::Upper_Lower_En_Decrypt(QString src) +{ + QByteArray result; + for(auto &i:src) + { + if(i.isUpper()) + { + QChar word = i.toLower(); + result.append(word.toLatin1()); + } + else if (i.isLower()) + { + QChar word = i.toUpper(); + result.append(word.toLatin1()); + } + else + result.append(i.toLatin1()); + } + return result; +} + +QByteArray Protocol::data_encrypt(QByteArray src) +{ + QByteArray en_base64 = src.toBase64(); + QByteArray result = Upper_Lower_En_Decrypt(en_base64); + return XOR_En_Decrypt(result); +} + +QByteArray Protocol::data_decrypt(QByteArray src) +{ + QByteArray result = XOR_En_Decrypt(src); + result = Upper_Lower_En_Decrypt(result); + return QByteArray::fromBase64(result); +} + +void Protocol::set_data_cipher_word(char word) +{ + cipher_word = word; +} diff --git a/protocol.h b/protocol.h new file mode 100644 index 0000000..0a2b08c --- /dev/null +++ b/protocol.h @@ -0,0 +1,59 @@ +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#include +#include + +class Protocol : public QObject +{ + Q_OBJECT +public: + static Protocol* getInstance(); + template + QByteArray data_maker(Type type, Args ...args) + { + QList args_list; + args_list.append(any_types(type)); + (void)std::initializer_list {(args_list.append(any_types(args)),0)...}; + return data_builder(args_list); + }; + enum data_types {MESSAGE,FILE,REQUEST,ONLINEUSERS,RESPONSE}; + QPair data_parser(QByteArray data); + QByteArray data_encrypt(QByteArray src); + void set_data_cipher_word(char word); + QByteArray data_decrypt(QByteArray src); +private: + char cipher_word = 'G'; + struct any_types { + enum type {String, Bool, Int, Data_types, List}; + any_types(int e) { m_data.INT = e; m_type = Int;} + any_types(QString e) { m_data.STRING=e; m_type = String;} + any_types(QList e) { m_data.LIST=e; m_type = List;} + any_types(bool e) { m_data.BOOL = e; m_type = Bool;} + any_types(data_types e) { m_data.DATA_TYPES = e; m_type = Data_types;} + type get_type() const { return m_type; } + int get_int() const { return m_data.INT; } + bool get_bool() const { return m_data.BOOL; } + data_types get_data_types() const { return m_data.DATA_TYPES; } + QString get_string() const { return m_data.STRING; } + QList get_list() const { return m_data.LIST; } + private: + type m_type; + struct { + int INT; + bool BOOL; + QString STRING; + QList LIST; + data_types DATA_TYPES; + } m_data; + }; + static Protocol protocol_instance; + explicit Protocol(QObject *parent = nullptr); + ~Protocol(); + QByteArray data_builder(QList &args); + QByteArray XOR_En_Decrypt(QString src); + QByteArray Upper_Lower_En_Decrypt(QString src); +signals: + +}; +#endif // PROTOCOL_H diff --git a/tcpclient.cpp b/tcpclient.cpp new file mode 100644 index 0000000..cbc5378 --- /dev/null +++ b/tcpclient.cpp @@ -0,0 +1,96 @@ +#include "tcpclient.h" +#include +#include +#include + +using namespace std; +TCPClient TCPClient::tcpclient_instance; +QTcpSocket TCPClient::socket; + +TCPClient::TCPClient(QObject *parent) + : QObject{parent} +{ + +} + +TCPClient::~TCPClient() +{ + +} + +TCPClient* TCPClient::getInstance() +{ + return &tcpclient_instance; +} + +void TCPClient::configAndrun() +{ + socket.setSocketOption(QAbstractSocket::KeepAliveOption,1); + socket.connectToHost(server_ip, server_port); + connect(&socket,&QTcpSocket::connected,this,&TCPClient::connected); + connect(&socket,&QTcpSocket::disconnected,this,&TCPClient::disconnected); + connect(&socket,&QTcpSocket::readyRead,this,&TCPClient::readSocket); +} + +void TCPClient::sendToserver(QByteArray &data) +{ + if (socket.isOpen()) + { + socket.write(data); + socket.waitForBytesWritten(2000); + } +} + +void TCPClient::setServer(QString IP, qint16 port) +{ + server_ip = IP; + server_port = port; +} + +void TCPClient::connected() +{ + emit TCPClientConnected(); + QString addr_t = socket.peerAddress().toString(); + QByteArray addr = addr_t.toLocal8Bit(); + printf("Connected to server at %.*s:%d.\n",addr.size(),addr.data(),socket.peerPort()); +} + +void TCPClient::disconnected() +{ + emit TCPClientDisconnected(); + printf("Disconnected from server.\n"); +} + +void TCPClient::readSocket() +{ + QByteArray recv; + while(socket.bytesAvailable())//循环接收 + { + recv += socket.readAll(); + if (!socket.waitForReadyRead(20))//超时停止接收 + { + /*QString error = sock->errorString(); + string error_t = error.toStdString(); + log_w("error:%d: %.*s", sock->error(),error_t.length(), error_t.data());*/ + break; + } + } + QString ip = socket.peerAddress().toString(); + string ip_t = ip.toStdString(); + printf("TCPC: Recvd from %.*s:%d\n", ip_t.length(), ip_t.data(), socket.peerPort()); + printf("TCPC Message:%.*s\n",recv.size(),(char *)recv.data()); + if (_callback != nullptr) + _callback(ip, socket.peerPort(),recv); +} + +void TCPClient::setCallBack(void (*callback)(QString &mac, quint16 port, QByteArray &data)) +{ + _callback = callback; +} + +void TCPClient::_sleep(int msec) +{ + QTime dieTime = QTime::currentTime().addMSecs(msec); + while( QTime::currentTime() < dieTime ) + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); +} diff --git a/tcpclient.h b/tcpclient.h new file mode 100644 index 0000000..5bc0db2 --- /dev/null +++ b/tcpclient.h @@ -0,0 +1,39 @@ +#ifndef TCPCLIENT_H +#define TCPCLIENT_H + +#include +#include +#include + +class TCPClient : public QObject +{ + Q_OBJECT +public: + static TCPClient* getInstance(); + static void sendToserver(QByteArray &data); + void configAndrun(); + void setCallBack(void (*callback)(QString &ip, quint16 port, QByteArray &data)); + void setServer(QString IP, qint16 port); +private slots: + void connected(); + void readSocket(); + void disconnected(); +private: + explicit TCPClient(QObject *parent = nullptr); + ~TCPClient(); + static void _sleep(int msec); + static QTcpSocket socket; + static TCPClient tcpclient_instance; + QString server_ip = "127.0.0.1"; + qint16 server_port = 7890; + bool has_found = false; + void (*_callback) (QString &ip, quint16 port, QByteArray &data)=nullptr; +signals: + void TCPClientConnected(); + void TCPClientDisconnected(); + +signals: + +}; + +#endif // TCPCLIENT_H diff --git a/tcpserver.cpp b/tcpserver.cpp new file mode 100644 index 0000000..e9aec66 --- /dev/null +++ b/tcpserver.cpp @@ -0,0 +1,121 @@ +#include "tcpserver.h" + +using namespace std; + +TCPServer TCPServer::tcpserver_instance; + +TCPServer::TCPServer(QObject *parent) + : QObject{parent} +{ + +} + +TCPServer::~TCPServer() +{ + +} + +TCPServer* TCPServer::getInstance() +{ + return &tcpserver_instance; +} + +void TCPServer::configAndrun() +{ + tcp_server.listen(QHostAddress(listen_addr), listen_port); + connect(&tcp_server, &QTcpServer::newConnection, this, &TCPServer::acceptTCPConnection); + QByteArray addr = listen_addr.toLocal8Bit(); + printf("TCP Server Started at %.*s:%d.\n", addr.length(), addr.data(),listen_port); +} + +void TCPServer::setServer(QString IP, qint16 port) +{ + listen_addr = IP; + listen_port = port; +} + +void TCPServer::stopRun() +{ + tcp_server.close(); + QByteArray addr = listen_addr.toLocal8Bit(); + printf("TCP Server Closed at %.*s:%d.\n",addr.length(), addr.data(),listen_port); +} + +void TCPServer::acceptTCPConnection() +{ + QTcpSocket* clientConnection = tcp_server.nextPendingConnection(); + if(clientConnection!=nullptr) + { + clientConnection->setParent(this); + tcp_socket_list.append(clientConnection); + connect(clientConnection, &QTcpSocket::readyRead, this, &TCPServer::TCPReadPeer); + connect(clientConnection,&QTcpSocket::disconnected,this,&TCPServer::discTCPConnection); + QString ip = clientConnection->peerAddress().toString(); + string ip_t = ip.toStdString(); + printf("TCP: %.*s:%d connected.\n",ip_t.length(), ip_t.data(), clientConnection->peerPort()); + } +} + +void TCPServer::discTCPConnection() +{ + for (int i=0;i(sender()))//可以直接用sender()解决,此处为稳健起见还是采取遍历 + { + QString ip = tcp_socket_list[i]->peerAddress().toString(); + string ip_t = ip.toStdString(); + printf("TCP: %.*s:%d Disconnected.\n",ip_t.length(), ip_t.data(), tcp_socket_list[i]->peerPort()); + if (disccallback != nullptr) + disccallback(ip, tcp_socket_list[i]->peerPort()); + tcp_socket_list.removeAt(i); + dynamic_cast(sender())->deleteLater(); + break; + } + } +} + +void TCPServer::TCPReadPeer() +{ + QTcpSocket* sock =(QTcpSocket *)sender(); + QByteArray recv; + while(sock->bytesAvailable())//循环接收 + { + recv += sock->readAll(); + if (!sock->waitForReadyRead(20))//超时停止接收 + { + /*QString error = sock->errorString(); + string error_t = error.toStdString(); + log_w("error:%d: %.*s", sock->error(),error_t.length(), error_t.data());*/ + break; + } + } + QString ip = sock->peerAddress().toString(); + string ip_t = ip.toStdString(); + printf("TCPC: Recvd from %.*s:%d\n", ip_t.length(), ip_t.data(), sock->peerPort()); + printf("TCP Message:%.*s\n",recv.size(),(char *)recv.data()); + if (recvcallback != nullptr) + recvcallback(ip, sock->peerPort(),recv); +} + +void TCPServer::setCallBack(void (*callback)(QString &ip, quint16 port, QByteArray &data)) +{ + recvcallback = callback; +} + +void TCPServer::setCallBack(void (*callback)(QString &ip, quint16 port)) +{ + disccallback = callback; +} + +void TCPServer::sendToclient(QString ip, quint16 port, QByteArray data) +{ + QHostAddress addr(ip); + for (int i=0;ipeerAddress()&&tcp_socket_list[i]->peerPort()==port) + { + tcp_socket_list[i]->write(data); + break; + } + } +} diff --git a/tcpserver.h b/tcpserver.h new file mode 100644 index 0000000..b13859c --- /dev/null +++ b/tcpserver.h @@ -0,0 +1,36 @@ +#ifndef TCPSERVER_H +#define TCPSERVER_H + +#include +#include +#include + +class TCPServer : public QObject +{ + Q_OBJECT +public: + static TCPServer* getInstance(); + void configAndrun(); + void setServer(QString IP, qint16 port); + void setCallBack(void (*callback)(QString &ip, quint16 port, QByteArray &data));//Qt的信号-槽机制实际就是回调函数, + void setCallBack(void (*callback)(QString &ip, quint16 port)); //此处为练手,不使用该机制 + void sendToclient(QString ip, quint16 port, QByteArray data); + void stopRun(); +private: + explicit TCPServer(QObject *parent = nullptr); + ~TCPServer(); + QString listen_addr = "0.0.0.0"; + qint16 listen_port = 7890; + QTcpServer tcp_server; + QList tcp_socket_list; + void (*recvcallback) (QString &ip, quint16 port, QByteArray &data)=nullptr; + void (*disccallback) (QString &ip, quint16 port)=nullptr; + static TCPServer tcpserver_instance; +private slots: + void acceptTCPConnection(); + void TCPReadPeer(); + void discTCPConnection(); +signals: +}; + +#endif // TCPSERVER_H