added base clent protockol

This commit is contained in:
Andrei Yankovich 2019-02-13 13:03:40 +03:00
parent 889b89d8cf
commit d4dc66ef6a
21 changed files with 635 additions and 113 deletions

View File

@ -0,0 +1,23 @@
#
# Copyright (C) 2018 - 2019 QuasarApp.
# Distributed under the lgplv3 software license, see the accompanying
# Everyone is permitted to copy and distribute verbatim copies
# of this license document, but changing it is not allowed.
#
!isEmpty(CLIENTPROTOCOL_LIB):error("ClientProtocol.pri already included")
CLIENTPROTOCOL_LIB = 1
#DEPENDS
CONFIG(release, debug|release): {
CLIENTPROTOCOL_LIB_OUTPUT_DIR="$$PWD/build/release"
} else {
CLIENTPROTOCOL_LIB_OUTPUT_DIR="$$PWD/build/debug"
}
LIBS += -L$$CLIENTPROTOCOL_LIB_OUTPUT_DIR -lClientProtocol
INCLUDEPATH += "$$PWD/"

View File

@ -1,3 +1,10 @@
#
# Copyright (C) 2018 - 2019 QuasarApp.
# Distributed under the lgplv3 software license, see the accompanying
# Everyone is permitted to copy and distribute verbatim copies
# of this license document, but changing it is not allowed.
#
#-------------------------------------------------
#
# Project created by QtCreator 2019-02-12T11:08:54
@ -5,6 +12,7 @@
#-------------------------------------------------
QT -= gui
QT += network
TARGET = ClientProtocol
TEMPLATE = lib
@ -35,16 +43,16 @@ SOURCES += \
clientprotocol.cpp \
player.cpp \
baseitem.cpp \
snakeitem.cpp
snakeitem.cpp \
client.cpp \
server.cpp
HEADERS += \
clientprotocol.h \
clientprotocol_global.h \
player.h \
baseitem.h \
snakeitem.h
unix {
target.path = /usr/lib
INSTALLS += target
}
snakeitem.h \
client.h \
server.h \
cp.h

View File

@ -1,8 +1,12 @@
#include "baseitem.h"
namespace ClientProtocol {
BaseItem::BaseItem() {
unsigned int BaseItem::id() const {
return _id;
}
BaseItem::BaseItem(unsigned int id) {
_id = id;
}
BaseItem::~BaseItem() {
@ -18,6 +22,10 @@ QDataStream& BaseItem::operator <<(QDataStream &stream) {
return stream;
}
bool BaseItem::operator ==(const BaseItem & item) {
return _id == item._id;
}
QDataStream &BaseItem::operator >>(QDataStream &stream) const{
stream << _id;

View File

@ -11,18 +11,19 @@ namespace ClientProtocol {
class CLIENTPROTOCOLSHARED_EXPORT BaseItem {
private:
unsigned int _id = 0;
protected:
BaseItem();
public:
explicit BaseItem(unsigned int _id);
virtual ~BaseItem();
virtual QDataStream &operator >>(QDataStream& stream) const;
virtual QDataStream &operator <<(QDataStream& stream);
bool operator ==(const BaseItem&);
virtual bool isValid();
friend ServerFactory;
unsigned int id() const;
};
}

View File

@ -0,0 +1,56 @@
#include "client.h"
#include <QTcpSocket>
namespace ClientProtocol {
void Client::incommingData() {
auto array = _destination->readAll();
if (_downloadPackage.hdr.isValid()) {
_downloadPackage.data.append(array);
} else {
memcpy(&_downloadPackage.hdr,
array.data(), sizeof(unsigned char));
_downloadPackage.data.append(array.mid(1));
}
if (_downloadPackage.isValid()) {
emit sigIncommingData(_downloadPackage.parse());
_downloadPackage.reset();
return;
}
}
Client::Client(QObject *ptr):
QObject (ptr) {
_destination = new QTcpSocket(this);
_destination->connectToHost(DEFAULT_SNAKE_SERVER, DEFAULT_SNAKE_PORT);
connect(_destination, &QTcpSocket::readyRead,
this, &Client::incommingData);
}
bool Client::sendPackage(const Package &pkg) {
if (!pkg.isValid()) {
return false;
}
if (!_destination->isValid()) {
qCritical() << "destination server not valid!";
return false;
}
if (!_destination->waitForConnected()) {
qCritical() << "no connected to server! " << _destination->errorString();
return false;
}
auto bytes = pkg.toBytes();
return bytes.size() == _destination->write(bytes);
}
}

View File

@ -0,0 +1,34 @@
#ifndef CLIENT_CP_H
#define CLIENT_CP_H
#include "clientprotocol_global.h"
#include "clientprotocol.h"
#include <QObject>
class QTcpSocket;
namespace ClientProtocol {
class CLIENTPROTOCOLSHARED_EXPORT Client: public QObject
{
Q_OBJECT
private:
QTcpSocket *_destination;
Package _downloadPackage;
private slots:
void incommingData();
public:
explicit Client(QObject * ptr = nullptr);
bool sendPackage(const Package& pkg);
signals:
void sigIncommingData(const QVariantMap& map);
};
}
#endif // CLIENT_CP_H

View File

@ -1 +1,90 @@
#include "clientprotocol.h"
#include <QVariantMap>
#define DEFAULT_GAME_PORT 7777
namespace ClientProtocol {
Header::Header() {
reset();
}
bool Header::isValid() const {
if (sizeof (*this) != 1) {
return false;
}
switch (command) {
case ping: {
if (type > 1)
return false;
return true;
}
default: return false;
}
}
void Header::reset() {
size = 0;
command = undefined;
type = Responke;
}
Package::Package() {
reset();
}
bool Package::isValid() const {
if (!hdr.isValid()) {
return false;
}
return hdr.size == data.size();
}
QVariantMap Package::parse() const {
if (!isValid())
return QVariantMap();
QVariantMap res;
switch (hdr.command) {
case ping: {
if (hdr.type == Responke) {
res["res"] = "Pong";
} else {
res["value"] = "Ping";
}
break;
}
default:
return res;
}
return res;
}
QByteArray Package::toBytes() const {
QByteArray res;
res.append(reinterpret_cast<char*>(const_cast<Header*>(&hdr)),
sizeof (hdr));
res.append(data);
return res;
}
void Package::reset() {
hdr.reset();
data.clear();
}
}

View File

@ -3,8 +3,98 @@
#include "clientprotocol_global.h"
namespace ClientProtocol {
#include <QVariantMap>
#define DEFAULT_SNAKE_SERVER "127.0.0.1"
#define LOCAL_SNAKE_SERVER "127.0.0.1"
#define DEFAULT_SNAKE_PORT 7777
namespace ClientProtocol {
enum Type: unsigned char {
Responke = 0,
Request = 1
};
enum Command: unsigned char {
undefined = 0x00,
ping = 0x01,
};
/**
* @brief The Header struct 1 byte
*/
struct Header {
/**
* @brief size - size of package data (not header)
*/
unsigned char size: 4;
/**
* @brief type of package see Type
*/
unsigned char type: 1;
/**
* @brief command of pacage see Command
*/
unsigned char command: 3;
/**
* @brief Header default constructor
*/
Header();
/**
* @brief isValid
* @return true if header is valid
*/
bool isValid() const;
/**
* @brief reset - reset all data and set for header invalid status
*/
void reset();
};
/**
* @brief The Package struct
*/
struct Package {
/**
* @brief hdr - header of package
*/
Header hdr;
/**
* @brief data - source data of package
*/
QByteArray data;
Package();
/**
* @brief isValid
* @return true if package is valid
*/
bool isValid() const;
/**
* @brief parse
* @return Qmap of package (default key if "value")
*/
QVariantMap parse() const;
/**
* @brief toBytes
* @return bytes array of packag
*/
QByteArray toBytes() const;
/**
* @brief reset - reset all data and set for package invalid status
*/
void reset();
};
}
#endif // CLIENTPROTOCOL_H

View File

@ -0,0 +1,6 @@
#ifndef CP_H
#define CP_H
#include "server.h"
#include "client.h"
#endif // CP_H

View File

@ -0,0 +1,96 @@
#include "server.h"
#include "quasarapp.h"
#include <QTcpSocket>
namespace ClientProtocol {
bool Server::parsePackage(const Package &pkg, QTcpSocket* sender) {
if (!pkg.isValid()) {
QuasarAppUtils::Params::verboseLog("incomming package is not valid!");
return false;
}
if (!sender->isValid()) {
QuasarAppUtils::Params::verboseLog("incomming package is not valid!");
return false;
}
switch (pkg.hdr.command) {
case ping: {
if (pkg.hdr.type != Responke) {
return false;
}
Package resp;
resp.hdr.command = ping;
auto bytes = resp.toBytes();
if (bytes.size() != sender->write(bytes)) {
QuasarAppUtils::Params::verboseLog("!responce not sendet!");
}
break;
}
default:{
QuasarAppUtils::Params::verboseLog("!responce not sendet!");
return false;
}
}
return true;
}
void Server::avelableBytes() {
auto client = dynamic_cast<QTcpSocket*>(sender());
if (!client) {
return;
}
auto array = client->readAll();
if (_downloadPackage.hdr.isValid()) {
_downloadPackage.data.append(array);
} else {
memcpy(&_downloadPackage.hdr,
array.data(), sizeof(unsigned char));
_downloadPackage.data.append(array.mid(1));
}
if (_downloadPackage.isValid()) {
parsePackage(_downloadPackage, client);
_downloadPackage.reset();
return;
}
}
void Server::handleIncommingConnection() {
while (hasPendingConnections()) {
auto socket = nextPendingConnection();
connect(socket, &QTcpSocket::readyRead, this, &Server::avelableBytes);
}
}
Server::Server(QObject *ptr) :
QTcpServer (ptr) {
connect(this, &Server::newConnection, this, &Server::handleIncommingConnection);
}
Server::~Server() {
}
bool Server::run(const QString &ip, unsigned short port) {
if (!listen(QHostAddress(ip), port) ) {
QuasarAppUtils::Params::verboseLog("listing fail " + this->errorString());
return false;
}
return true;
}
}

View File

@ -0,0 +1,31 @@
#ifndef SERVER_CP_H
#define SERVER_CP_H
#include "clientprotocol_global.h"
#include "clientprotocol.h"
#include <QTcpServer>
namespace ClientProtocol {
class CLIENTPROTOCOLSHARED_EXPORT Server : public QTcpServer
{
Q_OBJECT
private:
Package _downloadPackage;
bool parsePackage(const Package &pkg, QTcpSocket * sender);
private slots:
void avelableBytes();
void handleIncommingConnection();
public:
explicit Server(QObject * ptr = nullptr);
~Server() override;
bool run(const QString& ip, unsigned short port);
};
}
#endif // SERVER_CP_H

View File

@ -2,17 +2,22 @@
namespace ClientProtocol {
SnakeItem::SnakeItem() {
SnakeItem::SnakeItem(unsigned int id):
BaseItem (id) {
}
SnakeItem::~SnakeItem() {
}
bool SnakeItem::isValid() {
return BaseItem::isValid() && _spead > 0;
return BaseItem::isValid() && _spead > 0 && _skillet.size();
}
QDataStream &SnakeItem::operator <<(QDataStream &stream) {
BaseItem::operator<<(stream);
stream >> _spead;
stream >> _skillet;
return stream;
}
@ -21,9 +26,9 @@ QDataStream &SnakeItem::operator >>(QDataStream &stream) const {
BaseItem::operator>>(stream);
stream << _spead;
stream << _skillet;
return stream;
}
}

View File

@ -2,14 +2,18 @@
#define SNAKEITEM_H
#include "baseitem.h"
#include <QVector>
namespace ClientProtocol {
class SnakeItem: public BaseItem
class CLIENTPROTOCOLSHARED_EXPORT SnakeItem: public BaseItem
{
private:
unsigned int _spead = 0;
QVector<double> _skillet;
public:
SnakeItem();
explicit SnakeItem(unsigned int id);
~SnakeItem() override;
bool isValid() override;

View File

@ -37,8 +37,8 @@ DISTFILES += \
SOURCES += \
serverutils.cpp \
server.cpp \
serverprotocol.cpp \
server.cpp \
client.cpp
HEADERS += \
@ -46,5 +46,6 @@ HEADERS += \
serverprotocol_global.h \
serverutils.h \
server.h \
client.h
client.h \
sp.h

View File

@ -1,5 +1,5 @@
#ifndef CLIENT_H
#define CLIENT_H
#ifndef CLIENT_SP_H
#define CLIENT_SP_H
#include "serverprotocol.h"
#include "serverprotocol_global.h"
#include <QObject>
@ -29,4 +29,4 @@ signals:
}
#endif // CLIENT_H
#endif // CLIENT_SP_H

View File

@ -1,5 +1,5 @@
#ifndef SERVER_H
#define SERVER_H
#ifndef SERVER_SP_H
#define SERVER_SP_H
#include "serverprotocol.h"
#include "serverprotocol_global.h"
#include <QLocalServer>
@ -27,4 +27,4 @@ public:
bool run(const QString& name);
};
}
#endif // SERVER_H
#endif // SERVER_SP_H

View File

@ -6,7 +6,6 @@
#include <QVariantMap>
#define DEFAULT_SERVER "SnnakeServer"
#define DEFAULT_GAME_PORT 7777
namespace ServerProtocol {

View File

@ -0,0 +1,7 @@
#ifndef SP_H
#define SP_H
#include "server.h"
#include "client.h"
#endif // SP_H

View File

@ -7,7 +7,7 @@ CONFIG -= app_bundle
TEMPLATE = app
SOURCES += \
tst_testserverprotockol.cpp
tst_testsnakeserver.cpp
CONFIG(release, debug|release): {
DESTDIR = $$PWD/build/release
@ -18,3 +18,4 @@ CONFIG(release, debug|release): {
include($$PWD/../../QuasarAppLib/QuasarLib.pri)
include($$PWD/../ServerProtocol/ServerProtocol.pri)
include($$PWD/../ClientProtocol/ClientProtocol.pri)

View File

@ -1,85 +0,0 @@
#include <QtTest>
#include <server.h>
#include <client.h>
#include <thread>
#include <quasarapp.h>
#include <QCoreApplication>
// add necessary includes here
class testServerProtocol : public QObject
{
Q_OBJECT
public:
testServerProtocol();
~testServerProtocol();
private slots:
void initTestCase();
void cleanupTestCase();
void testPing();
};
testServerProtocol::testServerProtocol()
{
}
testServerProtocol::~testServerProtocol()
{
}
void testServerProtocol::initTestCase()
{
}
void testServerProtocol::cleanupTestCase()
{
}
void testServerProtocol::testPing()
{
QuasarAppUtils::Params::setEnable("verbose", true);
int argc =0;
char * argv[] = {nullptr};
QCoreApplication app(argc, argv);
auto serv = new ServerProtocol::Server(this);
QVERIFY(serv->run(DEFAULT_SERVER));
auto client = new ServerProtocol::Client(this);
bool isWork = false;
QObject::connect(client, &ServerProtocol::Client::sigIncommingData,
[&isWork, &app] (const QVariantMap& map) {
isWork = map["res"].toString() == "Pong";
app.exit(0);
});
ServerProtocol::Package pkg;
pkg.hdr.command = ServerProtocol::ping;
QVERIFY(client->sendPackage(pkg));
app.exec();
QVERIFY(isWork);
delete serv;
delete client;
}
QTEST_APPLESS_MAIN(testServerProtocol)
#include "tst_testserverprotockol.moc"

View File

@ -0,0 +1,148 @@
#include <QtTest>
#include <cp.h>
#include <sp.h>
#include <thread>
#include <quasarapp.h>
#include <QCoreApplication>
// add necessary includes here
class testSankeServer : public QObject
{
Q_OBJECT
private:
void testPingServerProtockol();
void testPingClientProtockol();
public:
testSankeServer();
~testSankeServer();
private slots:
void initTestCase();
void cleanupTestCase();
void testServerProtockol();
void testClientProtockol();
};
testSankeServer::testSankeServer()
{
}
testSankeServer::~testSankeServer()
{
}
void testSankeServer::initTestCase()
{
}
void testSankeServer::cleanupTestCase()
{
}
void testSankeServer::testPingServerProtockol()
{
QuasarAppUtils::Params::setEnable("verbose", true);
int argc =0;
char * argv[] = {nullptr};
QCoreApplication app(argc, argv);
auto serv = new ServerProtocol::Server(this);
QVERIFY(serv->run(DEFAULT_SERVER));
auto client = new ServerProtocol::Client(this);
bool isWork = false;
QObject::connect(client, &ServerProtocol::Client::sigIncommingData,
[&isWork, &app] (const QVariantMap& map) {
isWork = map["res"].toString() == "Pong";
app.exit(0);
});
ServerProtocol::Package pkg;
pkg.hdr.command = ServerProtocol::ping;
QVERIFY(client->sendPackage(pkg));
QTimer::singleShot(1000, [&app](){
app.exit(0);
});
app.exec();
QVERIFY(isWork);
delete serv;
delete client;
}
void testSankeServer::testPingClientProtockol() {
QuasarAppUtils::Params::setEnable("verbose", true);
int argc = 0;
char * argv[] = {nullptr};
QCoreApplication app(argc, argv);
auto serv = new ClientProtocol::Server(this);
QVERIFY(serv->run(LOCAL_SNAKE_SERVER, DEFAULT_SNAKE_PORT));
auto client = new ClientProtocol::Client(this);
bool isWork = false;
QObject::connect(client, &ClientProtocol::Client::sigIncommingData,
[&isWork, &app] (const QVariantMap& map) {
isWork = map["res"].toString() == "Pong";
app.exit(0);
});
ClientProtocol::Package pkg;
pkg.hdr.command = ClientProtocol::ping;
QVERIFY(client->sendPackage(pkg));
QTimer::singleShot(1000, [&app](){
app.exit(0);
});
app.exec();
QVERIFY(isWork);
delete serv;
delete client;
}
void testSankeServer::testServerProtockol() {
testPingServerProtockol();
}
void testSankeServer::testClientProtockol() {
testPingClientProtockol();
}
QTEST_APPLESS_MAIN(testSankeServer)
#include "tst_testsnakeserver.moc"