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