From fcf9f0f80e665880296f7304b163282db5512949 Mon Sep 17 00:00:00 2001 From: andrey Date: Tue, 6 Apr 2021 17:49:07 +0300 Subject: [PATCH] picloud add server logics --- libs/cloud/picloudclient.cpp | 24 +++++- libs/cloud/picloudserver.cpp | 86 ++++++++++++++++++--- libs/cloud/picloudtcp.cpp | 50 ++++++++++-- libs/main/cloud/picloudclient.h | 1 + libs/main/cloud/picloudserver.h | 18 ++++- libs/main/cloud/picloudtcp.h | 7 +- utils/cloud_dispatcher/cloudserver.cpp | 6 +- utils/cloud_dispatcher/dispatcherclient.cpp | 11 ++- utils/cloud_dispatcher/dispatcherclient.h | 1 + 9 files changed, 178 insertions(+), 26 deletions(-) diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index 01a3d29b..c5d960f6 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -24,6 +24,7 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode) { tcp.setRole(PICloud::TCP::Client); setName("cloud_client"); + is_connected = false; } @@ -67,6 +68,7 @@ bool PICloudClient::openDevice() { bool PICloudClient::closeDevice() { + is_connected = false; eth.stop(); eth.close(); return true; @@ -95,11 +97,25 @@ void PICloudClient::readed(uchar *data, int size) { mutex_buff.lock(); PIPair hdr = tcp.parseHeader(ba); if (hdr.second == tcp.role()) { - piCoutObj << "readed" << ba.toHex(); - buff.append(data, size); - cond_buff.notifyOne(); + switch (hdr.first) { + case PICloud::TCP::Connect: + if (tcp.parseConnect(ba) == 0) is_connected = true; + break; + case PICloud::TCP::Disconnect: + is_connected = false; + eth.stop(); + eth.close(); + break; + case PICloud::TCP::Data: + buff.append(data, size); + cond_buff.notifyOne(); + break; + default: + break; + } + //piCoutObj << "readed" << ba.toHex(); } mutex_buff.unlock(); - while (buff.size() > threadedReadBufferSize()) piMSleep(100); + while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); } diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 429c87b1..51ce349a 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -29,11 +29,12 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) PICloudServer::~PICloudServer() { - for (auto & c : clients) { - c.stop(); - c.close(); - } stop(); + eth.stop(); + for (auto & c : clients) { + c->stop(); + c->close(); + } close(); } @@ -66,9 +67,9 @@ bool PICloudServer::openDevice() { bool PICloudServer::closeDevice() { eth.stop(); - for (auto & c : clients) { - c.stop(); - c.close(); + for (auto c : clients) { + c->stop(); + c->close(); } eth.close(); return true; @@ -85,7 +86,17 @@ int PICloudServer::writeDevice(const void * data, int max_size) { } -PICloudServer::Client::Client(PICloudServer * srv) : server(srv) { +void PICloudServer::clientDisconnect(uint client_id) { + tcp.sendDisconnected(ð, client_id); +} + + +int PICloudServer::sendData(const PIByteArray & data, uint client_id) { + return tcp.sendData(ð, data, client_id); +} + + +PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), client_id(id) { } @@ -95,10 +106,67 @@ bool PICloudServer::Client::openDevice() { } +bool PICloudServer::Client::closeDevice() { + server->clientDisconnect(client_id); + return true; +} + + +int PICloudServer::Client::readDevice(void * read_to, int max_size) { + //piCoutObj << "readDevice"; + mutex_buff.lock(); + cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();}); + int sz = piMini(max_size, buff.size()); + memcpy(read_to, buff.data(), sz); + buff.remove(0, sz); + mutex_buff.unlock(); + return sz; +} + + +int PICloudServer::Client::writeDevice(const void * data, int max_size) { + return server->sendData(PIByteArray(data, max_size), client_id); +} + + +void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { + mutex_buff.lock(); + buff.append(ba); + cond_buff.notifyOne(); + mutex_buff.unlock(); + while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); +} + + void PICloudServer::readed(uchar *data, int size) { PIByteArray ba(data, size); PIPair hdr = tcp.parseHeader(ba); if (hdr.second == tcp.role()) { - piCoutObj << "readed" << ba.toHex(); + switch (hdr.first) { + case PICloud::TCP::Connect: { + uint id = tcp.parseConnect(ba); + Client * oc = index_clients.value(id, nullptr); + if (oc) { + tcp.sendDisconnected(ð, id); + } else { + Client * c = new Client(this, id); + clients << c; + index_clients.insert(id, c); + newConnection(c); + } + } break; + case PICloud::TCP::Disconnect: { + uint id = tcp.parseDisconnect(ba); + Client * oc = index_clients.value(id, nullptr); + if (oc) oc->close(); + } break; + case PICloud::TCP::Data: { + PIPair d = tcp.parseDataServer(ba); + Client * oc = index_clients.value(d.first, nullptr); + if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second); + } break; + default: + break; + } } } diff --git a/libs/cloud/picloudtcp.cpp b/libs/cloud/picloudtcp.cpp index 3c4cd892..642f7024 100644 --- a/libs/cloud/picloudtcp.cpp +++ b/libs/cloud/picloudtcp.cpp @@ -61,6 +61,14 @@ void PICloud::TCP::sendConnected(PIEthernet * eth, uint client_id) { } +void PICloud::TCP::sendDisconnected(PIEthernet * eth, uint client_id) { + header.type = PICloud::TCP::Disconnect; + PIByteArray ba; + ba << header << client_id; + eth->send(ba); +} + + void PICloud::TCP::sendData(PIEthernet * eth, const PIByteArray & data) { header.type = PICloud::TCP::Data; PIByteArray ba; @@ -71,6 +79,16 @@ void PICloud::TCP::sendData(PIEthernet * eth, const PIByteArray & data) { } +int PICloud::TCP::sendData(PIEthernet * eth, const PIByteArray & data, uint client_id) { + header.type = PICloud::TCP::Data; + PIByteArray ba; + ba << header << client_id; + ba.append(data); + if (eth->send(ba)) return data.size_s(); + else return -1; +} + + PIPair PICloud::TCP::parseHeader(PIByteArray & ba) { PIPair ret; ret.first = Invalid; @@ -88,11 +106,6 @@ PIPair PICloud::TCP::parseHeader(PIByteA PIByteArray PICloud::TCP::parseData(PIByteArray & ba) { - if (header.role == Server) { - PIString client; - ba >> client; - return ba; - } if (header.role == Client) { return ba; } @@ -100,8 +113,33 @@ PIByteArray PICloud::TCP::parseData(PIByteArray & ba) { } -PIString PICloud::TCP::parseConnect(PIByteArray & ba) { +PIPair PICloud::TCP::parseDataServer(PIByteArray & ba) { + PIPair ret; + ret.first = 0; + if (header.role == Server) { + ba >> ret.first; + ret.second = ba; + } + return ret; +} + + +PIString PICloud::TCP::parseConnect_d(PIByteArray & ba) { PIString ret; ba >> ret; return ret; } + + +uint PICloud::TCP::parseConnect(PIByteArray & ba) { + uint ret; + ba >> ret; + return ret; +} + + +uint PICloud::TCP::parseDisconnect(PIByteArray & ba) { + uint ret; + ba >> ret; + return ret; +} diff --git a/libs/main/cloud/picloudclient.h b/libs/main/cloud/picloudclient.h index 1d2513a7..08a0f0cd 100644 --- a/libs/main/cloud/picloudclient.h +++ b/libs/main/cloud/picloudclient.h @@ -49,6 +49,7 @@ private: PIByteArray buff; PIMutex mutex_buff; PIConditionVariable cond_buff; + std::atomic_bool is_connected; }; #endif // PICLOUDCLIENT_H diff --git a/libs/main/cloud/picloudserver.h b/libs/main/cloud/picloudserver.h index 2ab2a79d..cd762216 100644 --- a/libs/main/cloud/picloudserver.h +++ b/libs/main/cloud/picloudserver.h @@ -24,6 +24,7 @@ #define PICLOUDSERVER_H #include "picloudbase.h" +#include "piconditionvar.h" class PIP_CLOUD_EXPORT PICloudServer : public PIIODevice, private PICloudBase @@ -36,12 +37,22 @@ public: class Client : public PIIODevice { PIIODEVICE(PICloudServer::Client) + friend class PICloudServer; public: - Client(PICloudServer * srv = nullptr); + Client(PICloudServer * srv = nullptr, uint id = 0); protected: bool openDevice(); + bool closeDevice(); + int readDevice(void * read_to, int max_size); + int writeDevice(const void * data, int max_size); + private: + void pushBuffer(const PIByteArray & ba); PICloudServer * server; + uint client_id; + PIByteArray buff; + PIMutex mutex_buff; + PIConditionVariable cond_buff; }; void setServerName(const PIString & server_name); @@ -56,8 +67,11 @@ protected: private: EVENT_HANDLER2(void, readed, uchar * , data, int, size); + void clientDisconnect(uint client_id); + int sendData(const PIByteArray & data, uint client_id); - PIVector clients; + PIVector clients; + PIMap index_clients; }; #endif // PICLOUDSERVER_H diff --git a/libs/main/cloud/picloudtcp.h b/libs/main/cloud/picloudtcp.h index ca492e2d..a5201260 100644 --- a/libs/main/cloud/picloudtcp.h +++ b/libs/main/cloud/picloudtcp.h @@ -58,10 +58,15 @@ public: void sendStart(PIEthernet * eth); void sendConnected(PIEthernet * eth, uint client_id); + void sendDisconnected(PIEthernet * eth, uint client_id); void sendData(PIEthernet * eth, const PIByteArray & data); + int sendData(PIEthernet * eth, const PIByteArray & data, uint client_id); PIPair parseHeader(PIByteArray & ba); PIByteArray parseData(PIByteArray & ba); - PIString parseConnect(PIByteArray & ba); + PIPair parseDataServer(PIByteArray & ba); + PIString parseConnect_d(PIByteArray & ba); + uint parseConnect(PIByteArray & ba); + uint parseDisconnect(PIByteArray & ba); private: struct Header { diff --git a/utils/cloud_dispatcher/cloudserver.cpp b/utils/cloud_dispatcher/cloudserver.cpp index 80d27df4..66343413 100644 --- a/utils/cloud_dispatcher/cloudserver.cpp +++ b/utils/cloud_dispatcher/cloudserver.cpp @@ -40,7 +40,9 @@ void CloudServer::printStatus() { for (auto c: clients) { piCout << " " << c->address() << c->clientId(); } - for (auto c: clients) c->sendData(PIByteArray::fromHex("000000")); - server->sendData(PIByteArray::fromHex("000000")); + for (auto c: clients) { + c->sendData(PIByteArray::fromHex("000000")); + server->sendDataToClient(PIByteArray::fromHex("000000"), c->clientId()); + } } diff --git a/utils/cloud_dispatcher/dispatcherclient.cpp b/utils/cloud_dispatcher/dispatcherclient.cpp index e2a9ef48..7388466f 100644 --- a/utils/cloud_dispatcher/dispatcherclient.cpp +++ b/utils/cloud_dispatcher/dispatcherclient.cpp @@ -36,7 +36,14 @@ void DispatcherClient::sendConnected() { void DispatcherClient::sendData(const PIByteArray & data) { - tcp.sendData(eth, data); + if (tcp.role() == PICloud::TCP::Client) tcp.sendData(eth, data); + else piCoutObj << "error sendData, invalid role"; +} + + +void DispatcherClient::sendDataToClient(const PIByteArray & data, uint client_id) { + if (tcp.role() == PICloud::TCP::Server) tcp.sendData(eth, data, client_id); + else piCoutObj << "error sendDataToClient, invalid role"; } @@ -72,7 +79,7 @@ void DispatcherClient::readed(uchar *data, int size) { switch (hdr.first) { case PICloud::TCP::Connect: { tcp.setRole(hdr.second); - PIString sn = tcp.parseConnect(ba); + PIString sn = tcp.parseConnect_d(ba); if (hdr.second == PICloud::TCP::Server) registerServer(sn, this); if (hdr.second == PICloud::TCP::Client) registerClient(sn, this); return;} diff --git a/utils/cloud_dispatcher/dispatcherclient.h b/utils/cloud_dispatcher/dispatcherclient.h index 1584a6d8..2cd8acae 100644 --- a/utils/cloud_dispatcher/dispatcherclient.h +++ b/utils/cloud_dispatcher/dispatcherclient.h @@ -14,6 +14,7 @@ public: void close(); void sendConnected(); void sendData(const PIByteArray & data); + void sendDataToClient(const PIByteArray & data, uint client_id); PIString address(); uint clientId() const {return client_id;} EVENT1(disconnectEvent, DispatcherClient *, client)