diff --git a/AsioNetClientServer/asio_inet_client_server.pro b/AsioNetClientServer/asio_inet_client_server.pro
new file mode 100644
index 0000000..307d175
--- /dev/null
+++ b/AsioNetClientServer/asio_inet_client_server.pro
@@ -0,0 +1,34 @@
+CONFIG -= qt
+
+TEMPLATE = lib
+CONFIG += staticlib
+
+CONFIG += c++17
+
+INCLUDEPATH += ../EasyLoggingPP
+
+unix: CONFIG += link_pkgconfig
+unix: PKGCONFIG += libasio
+
+
+SOURCES += \
+
+LIBS += -pthread
+
+
+HEADERS += \
+ net_server_client.h \
+ src/net_client.h \
+ src/net_common.h \
+ src/net_connection.h \
+ src/net_dequeue_ts.h \
+ src/net_message.h \
+ src/net_message_types.h \
+ src/net_server.h
+
+
+# Default rules for deployment.
+unix {
+ target.path = $$[QT_INSTALL_PLUGINS]/generic
+}
+!isEmpty(target.path): INSTALLS += target
diff --git a/AsioNetClientServer/asio_inet_client_server.pro.user b/AsioNetClientServer/asio_inet_client_server.pro.user
new file mode 100644
index 0000000..2712cf1
--- /dev/null
+++ b/AsioNetClientServer/asio_inet_client_server.pro.user
@@ -0,0 +1,355 @@
+
+
+
+
+
+ EnvironmentId
+ {5a632e4a-e744-412b-acc7-3b951573dab3}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ Builtin.Questionable
+
+ true
+ Builtin.DefaultTidyAndClazy
+ 1
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 5.15.1 GCC 64bit
+ Desktop Qt 5.15.1 GCC 64bit
+ qt.qt5.5151.gcc_64_kit
+ 0
+ 0
+ 0
+
+ true
+ 0
+ /home/michael/baConditionMonitoring/AsioNetClientServer/debug
+ /home/michael/baConditionMonitoring/AsioNetClientServer/debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ 2
+ 2
+
+
+ true
+ 2
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Release
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 2
+
+
+ true
+ 0
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Profile
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+
+ false
+
+ false
+ true
+ false
+ false
+ true
+
+
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/AsioNetClientServer/asio_inet_client_server.pro.user.eac5e3e b/AsioNetClientServer/asio_inet_client_server.pro.user.eac5e3e
new file mode 100644
index 0000000..f93a819
--- /dev/null
+++ b/AsioNetClientServer/asio_inet_client_server.pro.user.eac5e3e
@@ -0,0 +1,317 @@
+
+
+
+
+
+ EnvironmentId
+ {eac5e3ee-8a8a-4d3e-ba79-20701eff322a}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ false
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ Builtin.BuildSystem
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 1
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 6.1.1 GCC 64bit
+ Desktop Qt 6.1.1 GCC 64bit
+ qt.qt6.611.gcc_64_kit
+ 1
+ 0
+ 0
+
+ 0
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Debug
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ debug
+ debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Profile
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+
+ 25
+
+ 1
+ true
+ false
+ true
+
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ false
+ true
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/AsioNetClientServer/net_server_client.h b/AsioNetClientServer/net_server_client.h
new file mode 100644
index 0000000..7510d99
--- /dev/null
+++ b/AsioNetClientServer/net_server_client.h
@@ -0,0 +1,64 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include "src/net_common.h"
+#include "src/net_dequeue_ts.h"
+#include "src/net_message.h"
+#include "src/net_client.h"
+#include "src/net_server.h"
+#include "src/net_connection.h"
diff --git a/AsioNetClientServer/src/net_client.h b/AsioNetClientServer/src/net_client.h
new file mode 100644
index 0000000..774834c
--- /dev/null
+++ b/AsioNetClientServer/src/net_client.h
@@ -0,0 +1,157 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+#include "net_common.h"
+#include "net_connection.h"
+namespace net
+{
+ template
+ class ClientInterface
+ {
+ public:
+ ClientInterface()
+ {}
+
+ virtual ~ClientInterface()
+ {
+ // If the client is destroyed, always try and disconnect from server
+ Disconnect();
+ }
+
+ public:
+ // Connect to server with hostname/ip-address and port
+ bool Connect(const std::string& host, const uint16_t port)
+ {
+ try
+ {
+ // Resolve hostname/ip-address into tangiable physical address
+ asio::ip::tcp::resolver resolver(m_context);
+ asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(host, std::to_string(port));
+
+ // Create connection
+ m_connection = std::make_unique>(Connection::Owner::CLIENT, m_context, asio::ip::tcp::socket(m_context), m_qMessagesIn);
+
+ // Tell the connection object to connect to server
+ m_connection->ConnectToServer(endpoints);
+
+ // Start Context Thread
+ thrContext = std::thread([this]() { m_context.run(); });
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Client Exception: " << e.what() << "\n";
+ return false;
+ }
+ return true;
+ }
+
+ // Disconnect from server
+ void Disconnect()
+ {
+ // If connection exists, and it's connected then...
+ if(IsConnected())
+ {
+ // ...disconnect from server gracefully
+ m_connection->Disconnect();
+ }
+
+ // Either way, we're also done with the asio context...
+ m_context.stop();
+ // ...and its thread
+ if (thrContext.joinable())
+ thrContext.join();
+
+ // Destroy the connection object
+ m_connection.release();
+ }
+
+ // Check if client is actually connected to a server
+ bool IsConnected()
+ {
+ if (m_connection)
+ return m_connection->IsConnected();
+ else
+ return false;
+ }
+
+ public:
+ // Send message to server
+ void Send(const Message& msg)
+ {
+ if (IsConnected())
+ m_connection->Send(msg);
+ }
+
+ // Retrieve queue of messages from server
+ net::ts_dequeue>& Incoming()
+ {
+ return m_qMessagesIn;
+ }
+
+ protected:
+ // asio context handles the data transfer...
+ asio::io_context m_context;
+ // ...but needs a thread of its own to execute its work commands
+ std::thread thrContext;
+ // The client has a single instance of a "connection" object, which handles data transfer
+ std::unique_ptr> m_connection;
+
+ private:
+ // This is the thread safe queue of incoming messages from server
+ net::ts_dequeue> m_qMessagesIn;
+ };
+}
diff --git a/AsioNetClientServer/src/net_common.h b/AsioNetClientServer/src/net_common.h
new file mode 100644
index 0000000..1dbd53a
--- /dev/null
+++ b/AsioNetClientServer/src/net_common.h
@@ -0,0 +1,76 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0A00
+#endif
+
+#define ASIO_STANDALONE
+#include
+#include
+#include
diff --git a/AsioNetClientServer/src/net_connection.h b/AsioNetClientServer/src/net_connection.h
new file mode 100644
index 0000000..3af8b3e
--- /dev/null
+++ b/AsioNetClientServer/src/net_connection.h
@@ -0,0 +1,343 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include "net_common.h"
+#include "net_dequeue_ts.h"
+#include "net_message.h"
+
+
+
+namespace net
+{
+ template
+ class Connection : public std::enable_shared_from_this>
+ {
+ public:
+ // A connection is "owned" by either a server or a client, and its
+ // behaviour is slightly different bewteen the two.
+ enum class Owner
+ {
+ SERVER,
+ CLIENT
+ };
+
+ public:
+ // Constructor: Specify Owner, connect to context, transfer the socket
+ // Provide reference to incoming message queue
+ Connection(Owner parent, asio::io_context& asioContext, asio::ip::tcp::socket socket, ts_dequeue>& qIn)
+ : m_socket(std::move(socket)), m_asioContext(asioContext), m_qMessagesIn(qIn)
+ {
+ m_nOwnerType = parent;
+ }
+
+ virtual ~Connection()
+ {}
+
+ // This ID is used system wide - its how clients will understand other clients
+ // exist across the whole system.
+ uint32_t GetID() const
+ {
+ return id;
+ }
+
+ public:
+ void ConnectToClient(uint32_t uid = 0)
+ {
+ if (m_nOwnerType == Owner::SERVER)
+ {
+ if (m_socket.is_open())
+ {
+ id = uid;
+ ReadHeader();
+ }
+ }
+ }
+
+ void ConnectToServer(const asio::ip::tcp::resolver::results_type& endpoints)
+ {
+ // Only clients can connect to servers
+ if (m_nOwnerType == Owner::CLIENT)
+ {
+ // Request asio attempts to connect to an endpoint
+ asio::async_connect(m_socket, endpoints,
+ [this](std::error_code ec, asio::ip::tcp::endpoint endpoint)
+ {
+ if (!ec)
+ {
+ ReadHeader();
+ }
+ });
+ }
+ }
+
+
+ void Disconnect()
+ {
+ if (IsConnected())
+ asio::post(m_asioContext, [this]() { m_socket.close(); });
+ }
+
+ bool IsConnected() const
+ {
+ return m_socket.is_open();
+ }
+
+ // Prime the connection to wait for incoming messages
+ void StartListening()
+ {
+
+ }
+
+ public:
+ // ASYNC - Send a message, connections are one-to-one so no need to specifiy
+ // the target, for a client, the target is the server and vice versa
+ void Send(const Message& msg)
+ {
+ asio::post(m_asioContext,
+ [this, msg]()
+ {
+ // If the queue has a message in it, then we must
+ // assume that it is in the process of asynchronously being written.
+ // Either way add the message to the queue to be output. If no messages
+ // were available to be written, then start the process of writing the
+ // message at the front of the queue.
+ bool bWritingMessage = !m_qMessagesOut.empty();
+ m_qMessagesOut.push_back(msg);
+ if (!bWritingMessage)
+ {
+ WriteHeader();
+ }
+ });
+ }
+
+
+
+ private:
+ // ASYNC - Prime context to write a message header
+ void WriteHeader()
+ {
+ // If this function is called, we know the outgoing message queue must have
+ // at least one message to send. So allocate a transmission buffer to hold
+ // the message, and issue the work - asio, send these bytes
+ asio::async_write(m_socket, asio::buffer(&m_qMessagesOut.front().header, sizeof(MessageHeader)),
+ [this](std::error_code ec, std::size_t length)
+ {
+ // asio has now sent the bytes - if there was a problem
+ // an error would be available...
+ if (!ec)
+ {
+ // ... no error, so check if the message header just sent also
+ // has a message body...
+ if (m_qMessagesOut.front().body.size() > 0)
+ {
+ // ...it does, so issue the task to write the body bytes
+ WriteBody();
+ }
+ else
+ {
+ // ...it didnt, so we are done with this message. Remove it from
+ // the outgoing message queue
+ m_qMessagesOut.pop_front();
+
+ // If the queue is not empty, there are more messages to send, so
+ // make this happen by issuing the task to send the next header.
+ if (!m_qMessagesOut.empty())
+ {
+ WriteHeader();
+ }
+ }
+ }
+ else
+ {
+ // ...asio failed to write the message, we could analyse why but
+ // for now simply assume the connection has died by closing the
+ // socket. When a future attempt to write to this client fails due
+ // to the closed socket, it will be tidied up.
+ std::cout << "[" << id << "] Write Header Fail.\n";
+ m_socket.close();
+ }
+ });
+ }
+
+ // ASYNC - Prime context to write a message body
+ void WriteBody()
+ {
+ // If this function is called, a header has just been sent, and that header
+ // indicated a body existed for this message. Fill a transmission buffer
+ // with the body data, and send it!
+ asio::async_write(m_socket, asio::buffer(m_qMessagesOut.front().body.data(), m_qMessagesOut.front().body.size()),
+ [this](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ // Sending was successful, so we are done with the message
+ // and remove it from the queue
+ m_qMessagesOut.pop_front();
+
+ // If the queue still has messages in it, then issue the task to
+ // send the next messages' header.
+ if (!m_qMessagesOut.empty())
+ {
+ WriteHeader();
+ }
+ }
+ else
+ {
+ // Sending failed, see WriteHeader() equivalent for description :P
+ std::cout << "[" << id << "] Write Body Fail.\n";
+ m_socket.close();
+ }
+ });
+ }
+
+ // ASYNC - Prime context ready to read a message header
+ void ReadHeader()
+ {
+ // asio to waits until it receives
+ // enough bytes to form a header of a message. We know the headers are a fixed
+ // size, so allocate a transmission buffer large enough to store it.
+ //Call this function to set up an asynchronous listener for a certain Connection
+ asio::async_read(m_socket, asio::buffer(&m_msgTemporaryIn.header, sizeof(MessageHeader)),
+ [this](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ //Full header readed
+ //Check for message body
+ if (m_msgTemporaryIn.header.size > 0)
+ {
+ //Allocate storage
+ m_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size);
+ //Read if available
+ ReadBody();
+ }
+ else
+ {
+ //Bodyless message, add to queue
+ AddToIncomingMessageQueue();
+ }
+ }
+ else
+ {
+ //Failure, probably a disconnection
+ std::cout << "[" << id << "] Error: " << ec.message() << std::endl;
+ m_socket.close();
+ }
+ });
+ }
+
+ // ASYNC - Prime context to read a message body
+ void ReadBody()
+ {
+ //Called after header has been read successfully
+ //Read the body in the pre allocated storage
+ asio::async_read(m_socket, asio::buffer(m_msgTemporaryIn.body.data(), m_msgTemporaryIn.body.size()),
+ [this](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ // Complete message, add to queue
+ AddToIncomingMessageQueue();
+ }
+ else
+ {
+ //Failure, probably a disconnection
+ std::cout << "[" << id << "] Error reading body: " << ec.message() << std::endl;
+ m_socket.close();
+ }
+ });
+ }
+
+ // Add a complete message to the incoming queue, with or without body
+ void AddToIncomingMessageQueue()
+ {
+ //Put it in the queue, put a owner to the object to let the server know who send the message (which connection)
+ if(m_nOwnerType == Owner::SERVER)
+ m_qMessagesIn.push_back({ this->shared_from_this(), m_msgTemporaryIn });
+ else
+ m_qMessagesIn.push_back({ nullptr, m_msgTemporaryIn });
+
+ //Done queueing the message, now initialize a new async read to wait for next message
+ ReadHeader();
+ }
+
+ protected:
+ // unique socket to a remote
+ asio::ip::tcp::socket m_socket;
+
+ // This context is shared with the whole asio instance
+ asio::io_context& m_asioContext;
+
+ // This queue holds all messages to be sent to the remote side
+ // of this connection
+ ts_dequeue> m_qMessagesOut;
+
+ // This references the incoming queue of the parent object
+ ts_dequeue>& m_qMessagesIn;
+
+ // Incoming messages are constructed asynchronously, so we will
+ // store the part assembled message here, until it is ready
+ Message m_msgTemporaryIn;
+
+ // The "owner" decides how some of the connection behaves
+ Owner m_nOwnerType = Owner::SERVER;
+
+ uint32_t id = 0;
+
+ };
+}
diff --git a/AsioNetClientServer/src/net_dequeue_ts.h b/AsioNetClientServer/src/net_dequeue_ts.h
new file mode 100644
index 0000000..69db4f0
--- /dev/null
+++ b/AsioNetClientServer/src/net_dequeue_ts.h
@@ -0,0 +1,161 @@
+/*
+MMO Client/Server Framework using ASIO
+"Happy Birthday Mrs Javidx9!" - javidx9
+
+Videos:
+Part #1: https://youtu.be/2hNdkYInj4g
+Part #2: https://youtu.be/UbjxGvrDrbw
+
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2018 - 2020 OneLoneCoder.com
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions or derivations of source code must retain the above
+copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce
+the above copyright notice. This list of conditions and the following
+disclaimer must be reproduced in the documentation and/or other
+materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Links
+~~~~~
+YouTube: https://www.youtube.com/javidx9
+Discord: https://discord.gg/WhwHUMV
+Twitter: https://www.twitter.com/javidx9
+Twitch: https://www.twitch.tv/javidx9
+GitHub: https://www.github.com/onelonecoder
+Homepage: https://www.onelonecoder.com
+
+Author
+~~~~~~
+David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include "net_common.h"
+
+
+namespace net
+{
+ template
+ class ts_dequeue
+ {
+ public:
+ ts_dequeue() = default;
+ ts_dequeue(const ts_dequeue&) = delete;
+ virtual ~ts_dequeue() { clear(); }
+
+ public:
+ // Returns and maintains item at front of Queue
+ const T& front()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.front();
+ }
+
+ // Returns and maintains item at back of Queue
+ const T& back()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.back();
+ }
+
+ // Removes and returns item from front of Queue
+ T pop_front()
+ {
+ std::scoped_lock lock(muxQueue);
+ auto t = std::move(deqQueue.front());
+ deqQueue.pop_front();
+ return t;
+ }
+
+ // Removes and returns item from back of Queue
+ T pop_back()
+ {
+ std::scoped_lock lock(muxQueue);
+ auto t = std::move(deqQueue.back());
+ deqQueue.pop_back();
+ return t;
+ }
+
+ // Adds an item to back of Queue
+ void push_back(const T& item)
+ {
+ std::scoped_lock lock(muxQueue);
+ deqQueue.emplace_back(std::move(item));
+
+ std::unique_lock ul(muxBlocking);
+ cvBlocking.notify_one();
+ }
+
+ // Adds an item to front of Queue
+ void push_front(const T& item)
+ {
+ std::scoped_lock lock(muxQueue);
+ deqQueue.emplace_front(std::move(item));
+
+ std::unique_lock ul(muxBlocking);
+ cvBlocking.notify_one();
+ }
+
+ // Returns true if Queue has no items
+ bool empty()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.empty();
+ }
+
+ // Returns number of items in Queue
+ size_t count()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.size();
+ }
+
+ // Clears Queue
+ void clear()
+ {
+ std::scoped_lock lock(muxQueue);
+ deqQueue.clear();
+ }
+
+ void wait()
+ {
+ while (empty())
+ {
+ std::unique_lock ul(muxBlocking);
+ cvBlocking.wait(ul);
+ }
+ }
+
+ protected:
+ std::mutex muxQueue;
+ std::deque deqQueue;
+ std::condition_variable cvBlocking;
+ std::mutex muxBlocking;
+ };
+}
diff --git a/AsioNetClientServer/src/net_message.h b/AsioNetClientServer/src/net_message.h
new file mode 100644
index 0000000..c332573
--- /dev/null
+++ b/AsioNetClientServer/src/net_message.h
@@ -0,0 +1,214 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, �OneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+#include "net_common.h"
+#include
+namespace net
+{
+ ///[OLC_HEADERIFYIER] START "MESSAGE"
+
+ // Message Header is sent at start of all messages. The template allows us
+ // to use "enum class" to ensure that the messages are valid at compile time
+ template
+ struct MessageHeader
+ {
+ T id{};
+ uint32_t size = 0;
+ };
+
+ // Message Body contains a header and a std::vector, containing raw bytes
+ // of infomation. This way the message can be variable length, but the size
+ // in the header must be updated.
+ template
+ struct Message
+ {
+ // Header & Body vector
+ MessageHeader header{};
+ std::vector body;
+
+
+ // returns size of entire message packet in bytes
+ size_t size() const
+ {
+ return body.size();
+ }
+
+ // Override for std::cout compatibility - produces friendly description of message
+ friend std::ostream& operator << (std::ostream& os, const Message& msg)
+ {
+ os << "ID:" << int(msg.header.id) << " Size:" << msg.header.size;
+ return os;
+ }
+
+ // Convenience Operator overloads - These allow us to add and remove stuff from
+ // the body vector as if it were a stack, so First in, Last Out. These are a
+ // template in itself, because we dont know what data type the user is pushing or
+ // popping, so lets allow them all. NOTE: It assumes the data type is fundamentally
+ // Plain Old Data (POD). TLDR: Serialise & Deserialise into/from a vector
+
+ // Pushes any POD-like data into the message buffer
+ template
+ friend Message& operator << (Message& msg, const DataType& data)
+ {
+ // Check that the type of the data being pushed is trivially copyable
+ static_assert(std::is_standard_layout::value, "Data is too complex to be pushed into vector");
+
+ // Cache current size of vector, as this will be the point we insert the data
+ size_t i = msg.body.size();
+
+ // Resize the vector by the size of the data being pushed
+ msg.body.resize(i + sizeof(DataType));
+
+ // Physically copy the data into the newly allocated vector space
+ std::memcpy(msg.body.data() + i, &data, sizeof(DataType));
+
+ // Recalculate the message size
+ msg.header.size = msg.size();
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ //Specified template to write string
+ friend Message& operator << (Message& msg, const std::string& data)
+ {
+ // Cache current size of vector, as this will be the point we insert the data
+ size_t i = msg.body.size();
+
+ // Resize the vector by the size of the data being pushed
+ //msg.body.resize(i + sizeof(data));
+
+ // Physically copy the data of the string character by character
+ msg.body.resize(i + data.size());
+
+ for (size_t index = 0; index < data.size(); index++) {
+ msg.body[i+index] = data.at(index);
+ //std::memcpy(msg.body.data() + i, &c, sizeof(uint8_t));
+ }
+
+ // Recalculate the message size
+ msg.header.size = (uint32_t)msg.size();
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ // Pulls any POD-like data form the message buffer
+ template
+ friend Message& operator >> (Message& msg, DataType& data)
+ {
+ // Check that the type of the data being pushed is trivially copyable
+ static_assert(std::is_standard_layout::value, "Data is too complex to be pulled from vector");
+
+ // Cache the location towards the end of the vector where the pulled data starts
+ size_t i = msg.body.size() - sizeof(DataType);
+
+ // Physically copy the data from the vector into the user variable
+ std::memcpy(&data, msg.body.data() + i, sizeof(DataType));
+
+ // Shrink the vector to remove read bytes, and reset end position
+ msg.body.resize(i);
+
+ // Recalculate the message size
+ msg.header.size = msg.size();
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ //Specified template to read string
+ friend Message& operator >> (Message& msg, std::string& data)
+ {
+ // Cache the location towards the end of the vector where the pulled data starts
+ size_t i = 0;
+
+ // Physically copy the data from the vector into the user variable
+ std::memcpy(&data, msg.body.data(), msg.body.size());
+
+ // Shrink the vector to remove read bytes, and reset end position
+ msg.body.resize(i);
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ };
+
+
+ // An "owned" message is identical to a regular message, but it is associated with
+ // a connection. On a server, the owner would be the client that sent the message,
+ // on a client the owner would be the server.
+
+ // Forward declare the connection
+ template
+ class Connection;
+
+ template
+ struct OwnedMessage
+ {
+ std::shared_ptr> remote = nullptr;
+ Message msg;
+
+ // Again, a friendly string maker
+ friend std::ostream& operator<<(std::ostream& os, const OwnedMessage& msg)
+ {
+ os << msg.msg;
+ return os;
+ }
+ };
+
+}
diff --git a/AsioNetClientServer/src/net_server.h b/AsioNetClientServer/src/net_server.h
new file mode 100644
index 0000000..3559a2c
--- /dev/null
+++ b/AsioNetClientServer/src/net_server.h
@@ -0,0 +1,279 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ?OneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+#include "net_dequeue_ts.h"
+#include "net_common.h"
+#include "net_message.h"
+#include "net_connection.h"
+#include "easylogging++.h"
+
+namespace net
+{
+ template
+ class ServerInterface
+ {
+ public: // Create a server, ready to listen on specified port
+ ServerInterface(uint16_t port)
+ : m_asioAcceptor(m_asioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) { }
+
+ virtual ~ServerInterface() { Stop(); }
+
+ // Starts the server
+ virtual bool Start()
+ {
+ try
+ {
+ // Issue a task to the asio context - This is important
+ // as it will prime the context with "work", and stop it
+ // from exiting immediately. Since this is a server, we
+ // want it primed ready to handle clients trying to
+ // connect.
+ WaitForClientConnection();
+ // Launch the asio context in its own thread
+ m_threadContext = std::thread([this]() { m_asioContext.run(); });
+ }
+ catch (std::exception& e)
+ {
+ // Something prohibited the server from listening
+ std::cerr << "[SERVER] Exception: " << e.what() << "\n";
+ return false;
+ }
+
+ LOG(INFO) << "[SERVER] Started\n";
+ return true;
+ }
+
+ bool isStopped()const {
+ return m_asioContext.stopped();
+ }
+
+ // Stops the server!
+ virtual void Stop()
+ {
+ // Request the context to close
+ m_asioContext.stop();
+
+ // Tidy up the context thread
+ if (m_threadContext.joinable()) m_threadContext.join();
+
+ // Inform someone, anybody, if they care...
+ LOG(INFO) << "[SERVER] Stopped!\n";
+ }
+
+ // ASYNC - Instruct asio to wait for connection
+ void WaitForClientConnection()
+ {
+ // Prime context with an instruction to wait until a socket connects. This
+ // is the purpose of an "acceptor" object. It will provide a unique socket
+ // for each incoming connection attempt
+ m_asioAcceptor.async_accept(
+ [this](std::error_code ec, asio::ip::tcp::socket socket)
+ {
+ // Triggered by incoming connection request
+ if (!ec)
+ {
+ LOG(INFO) << "[SERVER] New Connection: " << socket.remote_endpoint();
+
+ // Create a new connection to handle this client
+ std::shared_ptr> newconn =
+ std::make_shared>(Connection::Owner::SERVER,
+ m_asioContext, std::move(socket), m_qMessagesIn);
+
+
+ // Give the user server a chance to deny connection
+ if (OnClientConnect(newconn))
+ {
+ // Connection allowed, so add to container of new connections
+ m_deqConnections.push_back(std::move(newconn));
+
+ // Issue a task to the connection's
+ // asio context to sit and wait for bytes to arrive!
+ m_deqConnections.back()->ConnectToClient(nIDCounter++);
+
+ LOG(INFO) << "[" << m_deqConnections.back()->GetID() << "] Connection Approved\n";
+ }
+ else
+ {
+ LOG(INFO) << "[SERVER] Connection Denied";
+
+ // Connection will go out of scope with no pending tasks, so will
+ // get destroyed automatically (smart pointer)
+ }
+ }
+ else
+ {
+ // Error has occurred during acceptance
+ LOG(INFO) << "[SERVER] New Connection Error: " << ec.message();
+ }
+
+ // Prime the asio context with more work - again simply wait for
+ // another connection...
+ WaitForClientConnection();
+ });
+ }
+
+ // Send a message to a specific client
+ void MessageClient(std::shared_ptr> client, const Message& msg)
+ {
+ // Check client is legitimate...
+ if (client && client->IsConnected())
+ {
+ // ...and post the message via the connection
+ client->Send(msg);
+ }
+ else
+ {
+ // If we cant communicate with client then we may as
+ // well remove the client - let the server know, it may
+ // be tracking it somehow
+ OnClientDisconnect(client);
+
+ // Off you go now, bye bye!
+ client.reset();
+
+ // Then physically remove it from the container
+ m_deqConnections.erase(
+ std::remove(m_deqConnections.begin(), m_deqConnections.end(), client), m_deqConnections.end());
+ }
+ }
+
+ // Send message to all clients
+ void MessageAllClients(const Message& msg, std::shared_ptr> pIgnoreClient = nullptr)
+ {
+ bool bInvalidClientExists = false;
+
+ // Iterate through all clients in container
+ for (auto& client : m_deqConnections)
+ {
+ // Check client is connected...
+ if (client && client->IsConnected())
+ {
+ // ..it is!
+ if(client != pIgnoreClient)
+ client->Send(msg);
+ }
+ else
+ {
+ // The client couldnt be contacted, so assume it has
+ // disconnected.
+ OnClientDisconnect(client);
+ client.reset();
+
+ // Set this flag to then remove dead clients from container
+ bInvalidClientExists = true;
+ }
+ }
+
+ // Remove dead clients, all in one go - this way, we dont invalidate the
+ // container as we iterated through it.
+ if (bInvalidClientExists)
+ m_deqConnections.erase(
+ std::remove(m_deqConnections.begin(), m_deqConnections.end(), nullptr), m_deqConnections.end());
+ }
+
+ // Force server to respond to incoming messages
+ // size_t nmaxMessages: Assign -1 to unsigned to unspecify max message count
+ // bool bWait: if queue is empty, wait synchronously until message arrives
+ void Update(size_t nMaxMessages = -1, bool bWait = false)
+ {
+ if (bWait) m_qMessagesIn.wait();
+
+ // Process as many messages as you can up to the value
+ // specified
+ size_t nMessageCount = 0;
+ while (nMessageCount < nMaxMessages && !m_qMessagesIn.empty())
+ {
+ // Grab the front message
+ auto msg = m_qMessagesIn.pop_front();
+
+ // Pass to message handler
+ OnMessage(msg.remote, msg.msg);
+
+ nMessageCount++;
+ }
+ }
+
+ protected:
+ //Overwritable functions to customize server behaviour
+
+ // Called when a client connects, you can veto the connection by returning false
+ virtual bool OnClientConnect(std::shared_ptr> client) = 0;
+ // Called when a client appears to have disconnected
+ virtual void OnClientDisconnect(std::shared_ptr> client) = 0;
+
+ // Called when a message arrives
+ virtual void OnMessage(std::shared_ptr> client, Message& msg) = 0;
+
+
+ protected:
+ // Thread Safe Queue for incoming message packets
+ ts_dequeue> m_qMessagesIn;
+
+ // Container of active validated connections
+ std::deque>> m_deqConnections;
+
+ // Order of declaration is important - it is also the order of initialisation
+ asio::io_context m_asioContext;
+ std::thread m_threadContext;
+
+ // These things need an asio context
+ asio::ip::tcp::acceptor m_asioAcceptor; // Handles new incoming connection attempts...
+
+ // Clients will be identified in the "wider system" via an ID
+ uint32_t nIDCounter = 100;
+ };
+}
diff --git a/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro b/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro
new file mode 100644
index 0000000..307d175
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro
@@ -0,0 +1,34 @@
+CONFIG -= qt
+
+TEMPLATE = lib
+CONFIG += staticlib
+
+CONFIG += c++17
+
+INCLUDEPATH += ../EasyLoggingPP
+
+unix: CONFIG += link_pkgconfig
+unix: PKGCONFIG += libasio
+
+
+SOURCES += \
+
+LIBS += -pthread
+
+
+HEADERS += \
+ net_server_client.h \
+ src/net_client.h \
+ src/net_common.h \
+ src/net_connection.h \
+ src/net_dequeue_ts.h \
+ src/net_message.h \
+ src/net_message_types.h \
+ src/net_server.h
+
+
+# Default rules for deployment.
+unix {
+ target.path = $$[QT_INSTALL_PLUGINS]/generic
+}
+!isEmpty(target.path): INSTALLS += target
diff --git a/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro.user b/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro.user
new file mode 100644
index 0000000..2712cf1
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro.user
@@ -0,0 +1,355 @@
+
+
+
+
+
+ EnvironmentId
+ {5a632e4a-e744-412b-acc7-3b951573dab3}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ Builtin.Questionable
+
+ true
+ Builtin.DefaultTidyAndClazy
+ 1
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 5.15.1 GCC 64bit
+ Desktop Qt 5.15.1 GCC 64bit
+ qt.qt5.5151.gcc_64_kit
+ 0
+ 0
+ 0
+
+ true
+ 0
+ /home/michael/baConditionMonitoring/AsioNetClientServer/debug
+ /home/michael/baConditionMonitoring/AsioNetClientServer/debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ 2
+ 2
+
+
+ true
+ 2
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Release
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 2
+
+
+ true
+ 0
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Profile
+ /home/michael/baConditionMonitoring/build-asio_inet_client_server-Desktop_Qt_5_15_1_GCC_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+
+ false
+
+ false
+ true
+ false
+ false
+ true
+
+
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro.user.eac5e3e b/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro.user.eac5e3e
new file mode 100644
index 0000000..f93a819
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/asio_inet_client_server.pro.user.eac5e3e
@@ -0,0 +1,317 @@
+
+
+
+
+
+ EnvironmentId
+ {eac5e3ee-8a8a-4d3e-ba79-20701eff322a}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ false
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ Builtin.BuildSystem
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 1
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 6.1.1 GCC 64bit
+ Desktop Qt 6.1.1 GCC 64bit
+ qt.qt6.611.gcc_64_kit
+ 1
+ 0
+ 0
+
+ 0
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Debug
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ debug
+ debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Profile
+ /home/michael/baConditionMonitoring/AsioNetClientServer/build-asio_inet_client_server-Desktop_Qt_6_1_1_GCC_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+
+ 25
+
+ 1
+ true
+ false
+ true
+
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ false
+ true
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/ClientSimulation/AsioNetClientServer/net_server_client.h b/ClientSimulation/AsioNetClientServer/net_server_client.h
new file mode 100644
index 0000000..43eb6d7
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/net_server_client.h
@@ -0,0 +1,78 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+
+namespace net {
+ enum class MessageTypes
+ {
+ ServerAccept,
+ ServerDeny,
+ ServerData,
+ ServerLog,
+ ServerCondition,
+ ServerAlert,
+ ServerCloseConnection,
+ };
+}
+
+#include "src/net_common.h"
+#include "src/net_dequeue_ts.h"
+#include "src/net_message.h"
+#include "src/net_client.h"
+#include "src/net_server.h"
+#include "src/net_connection.h"
diff --git a/ClientSimulation/AsioNetClientServer/src/net_client.h b/ClientSimulation/AsioNetClientServer/src/net_client.h
new file mode 100644
index 0000000..774834c
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/src/net_client.h
@@ -0,0 +1,157 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+#include "net_common.h"
+#include "net_connection.h"
+namespace net
+{
+ template
+ class ClientInterface
+ {
+ public:
+ ClientInterface()
+ {}
+
+ virtual ~ClientInterface()
+ {
+ // If the client is destroyed, always try and disconnect from server
+ Disconnect();
+ }
+
+ public:
+ // Connect to server with hostname/ip-address and port
+ bool Connect(const std::string& host, const uint16_t port)
+ {
+ try
+ {
+ // Resolve hostname/ip-address into tangiable physical address
+ asio::ip::tcp::resolver resolver(m_context);
+ asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(host, std::to_string(port));
+
+ // Create connection
+ m_connection = std::make_unique>(Connection::Owner::CLIENT, m_context, asio::ip::tcp::socket(m_context), m_qMessagesIn);
+
+ // Tell the connection object to connect to server
+ m_connection->ConnectToServer(endpoints);
+
+ // Start Context Thread
+ thrContext = std::thread([this]() { m_context.run(); });
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Client Exception: " << e.what() << "\n";
+ return false;
+ }
+ return true;
+ }
+
+ // Disconnect from server
+ void Disconnect()
+ {
+ // If connection exists, and it's connected then...
+ if(IsConnected())
+ {
+ // ...disconnect from server gracefully
+ m_connection->Disconnect();
+ }
+
+ // Either way, we're also done with the asio context...
+ m_context.stop();
+ // ...and its thread
+ if (thrContext.joinable())
+ thrContext.join();
+
+ // Destroy the connection object
+ m_connection.release();
+ }
+
+ // Check if client is actually connected to a server
+ bool IsConnected()
+ {
+ if (m_connection)
+ return m_connection->IsConnected();
+ else
+ return false;
+ }
+
+ public:
+ // Send message to server
+ void Send(const Message& msg)
+ {
+ if (IsConnected())
+ m_connection->Send(msg);
+ }
+
+ // Retrieve queue of messages from server
+ net::ts_dequeue>& Incoming()
+ {
+ return m_qMessagesIn;
+ }
+
+ protected:
+ // asio context handles the data transfer...
+ asio::io_context m_context;
+ // ...but needs a thread of its own to execute its work commands
+ std::thread thrContext;
+ // The client has a single instance of a "connection" object, which handles data transfer
+ std::unique_ptr> m_connection;
+
+ private:
+ // This is the thread safe queue of incoming messages from server
+ net::ts_dequeue> m_qMessagesIn;
+ };
+}
diff --git a/ClientSimulation/AsioNetClientServer/src/net_common.h b/ClientSimulation/AsioNetClientServer/src/net_common.h
new file mode 100644
index 0000000..1dbd53a
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/src/net_common.h
@@ -0,0 +1,76 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0A00
+#endif
+
+#define ASIO_STANDALONE
+#include
+#include
+#include
diff --git a/ClientSimulation/AsioNetClientServer/src/net_connection.h b/ClientSimulation/AsioNetClientServer/src/net_connection.h
new file mode 100644
index 0000000..3af8b3e
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/src/net_connection.h
@@ -0,0 +1,343 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include "net_common.h"
+#include "net_dequeue_ts.h"
+#include "net_message.h"
+
+
+
+namespace net
+{
+ template
+ class Connection : public std::enable_shared_from_this>
+ {
+ public:
+ // A connection is "owned" by either a server or a client, and its
+ // behaviour is slightly different bewteen the two.
+ enum class Owner
+ {
+ SERVER,
+ CLIENT
+ };
+
+ public:
+ // Constructor: Specify Owner, connect to context, transfer the socket
+ // Provide reference to incoming message queue
+ Connection(Owner parent, asio::io_context& asioContext, asio::ip::tcp::socket socket, ts_dequeue>& qIn)
+ : m_socket(std::move(socket)), m_asioContext(asioContext), m_qMessagesIn(qIn)
+ {
+ m_nOwnerType = parent;
+ }
+
+ virtual ~Connection()
+ {}
+
+ // This ID is used system wide - its how clients will understand other clients
+ // exist across the whole system.
+ uint32_t GetID() const
+ {
+ return id;
+ }
+
+ public:
+ void ConnectToClient(uint32_t uid = 0)
+ {
+ if (m_nOwnerType == Owner::SERVER)
+ {
+ if (m_socket.is_open())
+ {
+ id = uid;
+ ReadHeader();
+ }
+ }
+ }
+
+ void ConnectToServer(const asio::ip::tcp::resolver::results_type& endpoints)
+ {
+ // Only clients can connect to servers
+ if (m_nOwnerType == Owner::CLIENT)
+ {
+ // Request asio attempts to connect to an endpoint
+ asio::async_connect(m_socket, endpoints,
+ [this](std::error_code ec, asio::ip::tcp::endpoint endpoint)
+ {
+ if (!ec)
+ {
+ ReadHeader();
+ }
+ });
+ }
+ }
+
+
+ void Disconnect()
+ {
+ if (IsConnected())
+ asio::post(m_asioContext, [this]() { m_socket.close(); });
+ }
+
+ bool IsConnected() const
+ {
+ return m_socket.is_open();
+ }
+
+ // Prime the connection to wait for incoming messages
+ void StartListening()
+ {
+
+ }
+
+ public:
+ // ASYNC - Send a message, connections are one-to-one so no need to specifiy
+ // the target, for a client, the target is the server and vice versa
+ void Send(const Message& msg)
+ {
+ asio::post(m_asioContext,
+ [this, msg]()
+ {
+ // If the queue has a message in it, then we must
+ // assume that it is in the process of asynchronously being written.
+ // Either way add the message to the queue to be output. If no messages
+ // were available to be written, then start the process of writing the
+ // message at the front of the queue.
+ bool bWritingMessage = !m_qMessagesOut.empty();
+ m_qMessagesOut.push_back(msg);
+ if (!bWritingMessage)
+ {
+ WriteHeader();
+ }
+ });
+ }
+
+
+
+ private:
+ // ASYNC - Prime context to write a message header
+ void WriteHeader()
+ {
+ // If this function is called, we know the outgoing message queue must have
+ // at least one message to send. So allocate a transmission buffer to hold
+ // the message, and issue the work - asio, send these bytes
+ asio::async_write(m_socket, asio::buffer(&m_qMessagesOut.front().header, sizeof(MessageHeader)),
+ [this](std::error_code ec, std::size_t length)
+ {
+ // asio has now sent the bytes - if there was a problem
+ // an error would be available...
+ if (!ec)
+ {
+ // ... no error, so check if the message header just sent also
+ // has a message body...
+ if (m_qMessagesOut.front().body.size() > 0)
+ {
+ // ...it does, so issue the task to write the body bytes
+ WriteBody();
+ }
+ else
+ {
+ // ...it didnt, so we are done with this message. Remove it from
+ // the outgoing message queue
+ m_qMessagesOut.pop_front();
+
+ // If the queue is not empty, there are more messages to send, so
+ // make this happen by issuing the task to send the next header.
+ if (!m_qMessagesOut.empty())
+ {
+ WriteHeader();
+ }
+ }
+ }
+ else
+ {
+ // ...asio failed to write the message, we could analyse why but
+ // for now simply assume the connection has died by closing the
+ // socket. When a future attempt to write to this client fails due
+ // to the closed socket, it will be tidied up.
+ std::cout << "[" << id << "] Write Header Fail.\n";
+ m_socket.close();
+ }
+ });
+ }
+
+ // ASYNC - Prime context to write a message body
+ void WriteBody()
+ {
+ // If this function is called, a header has just been sent, and that header
+ // indicated a body existed for this message. Fill a transmission buffer
+ // with the body data, and send it!
+ asio::async_write(m_socket, asio::buffer(m_qMessagesOut.front().body.data(), m_qMessagesOut.front().body.size()),
+ [this](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ // Sending was successful, so we are done with the message
+ // and remove it from the queue
+ m_qMessagesOut.pop_front();
+
+ // If the queue still has messages in it, then issue the task to
+ // send the next messages' header.
+ if (!m_qMessagesOut.empty())
+ {
+ WriteHeader();
+ }
+ }
+ else
+ {
+ // Sending failed, see WriteHeader() equivalent for description :P
+ std::cout << "[" << id << "] Write Body Fail.\n";
+ m_socket.close();
+ }
+ });
+ }
+
+ // ASYNC - Prime context ready to read a message header
+ void ReadHeader()
+ {
+ // asio to waits until it receives
+ // enough bytes to form a header of a message. We know the headers are a fixed
+ // size, so allocate a transmission buffer large enough to store it.
+ //Call this function to set up an asynchronous listener for a certain Connection
+ asio::async_read(m_socket, asio::buffer(&m_msgTemporaryIn.header, sizeof(MessageHeader)),
+ [this](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ //Full header readed
+ //Check for message body
+ if (m_msgTemporaryIn.header.size > 0)
+ {
+ //Allocate storage
+ m_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size);
+ //Read if available
+ ReadBody();
+ }
+ else
+ {
+ //Bodyless message, add to queue
+ AddToIncomingMessageQueue();
+ }
+ }
+ else
+ {
+ //Failure, probably a disconnection
+ std::cout << "[" << id << "] Error: " << ec.message() << std::endl;
+ m_socket.close();
+ }
+ });
+ }
+
+ // ASYNC - Prime context to read a message body
+ void ReadBody()
+ {
+ //Called after header has been read successfully
+ //Read the body in the pre allocated storage
+ asio::async_read(m_socket, asio::buffer(m_msgTemporaryIn.body.data(), m_msgTemporaryIn.body.size()),
+ [this](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ // Complete message, add to queue
+ AddToIncomingMessageQueue();
+ }
+ else
+ {
+ //Failure, probably a disconnection
+ std::cout << "[" << id << "] Error reading body: " << ec.message() << std::endl;
+ m_socket.close();
+ }
+ });
+ }
+
+ // Add a complete message to the incoming queue, with or without body
+ void AddToIncomingMessageQueue()
+ {
+ //Put it in the queue, put a owner to the object to let the server know who send the message (which connection)
+ if(m_nOwnerType == Owner::SERVER)
+ m_qMessagesIn.push_back({ this->shared_from_this(), m_msgTemporaryIn });
+ else
+ m_qMessagesIn.push_back({ nullptr, m_msgTemporaryIn });
+
+ //Done queueing the message, now initialize a new async read to wait for next message
+ ReadHeader();
+ }
+
+ protected:
+ // unique socket to a remote
+ asio::ip::tcp::socket m_socket;
+
+ // This context is shared with the whole asio instance
+ asio::io_context& m_asioContext;
+
+ // This queue holds all messages to be sent to the remote side
+ // of this connection
+ ts_dequeue> m_qMessagesOut;
+
+ // This references the incoming queue of the parent object
+ ts_dequeue>& m_qMessagesIn;
+
+ // Incoming messages are constructed asynchronously, so we will
+ // store the part assembled message here, until it is ready
+ Message m_msgTemporaryIn;
+
+ // The "owner" decides how some of the connection behaves
+ Owner m_nOwnerType = Owner::SERVER;
+
+ uint32_t id = 0;
+
+ };
+}
diff --git a/ClientSimulation/AsioNetClientServer/src/net_dequeue_ts.h b/ClientSimulation/AsioNetClientServer/src/net_dequeue_ts.h
new file mode 100644
index 0000000..69db4f0
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/src/net_dequeue_ts.h
@@ -0,0 +1,161 @@
+/*
+MMO Client/Server Framework using ASIO
+"Happy Birthday Mrs Javidx9!" - javidx9
+
+Videos:
+Part #1: https://youtu.be/2hNdkYInj4g
+Part #2: https://youtu.be/UbjxGvrDrbw
+
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2018 - 2020 OneLoneCoder.com
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions or derivations of source code must retain the above
+copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce
+the above copyright notice. This list of conditions and the following
+disclaimer must be reproduced in the documentation and/or other
+materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Links
+~~~~~
+YouTube: https://www.youtube.com/javidx9
+Discord: https://discord.gg/WhwHUMV
+Twitter: https://www.twitter.com/javidx9
+Twitch: https://www.twitch.tv/javidx9
+GitHub: https://www.github.com/onelonecoder
+Homepage: https://www.onelonecoder.com
+
+Author
+~~~~~~
+David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+
+#include "net_common.h"
+
+
+namespace net
+{
+ template
+ class ts_dequeue
+ {
+ public:
+ ts_dequeue() = default;
+ ts_dequeue(const ts_dequeue&) = delete;
+ virtual ~ts_dequeue() { clear(); }
+
+ public:
+ // Returns and maintains item at front of Queue
+ const T& front()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.front();
+ }
+
+ // Returns and maintains item at back of Queue
+ const T& back()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.back();
+ }
+
+ // Removes and returns item from front of Queue
+ T pop_front()
+ {
+ std::scoped_lock lock(muxQueue);
+ auto t = std::move(deqQueue.front());
+ deqQueue.pop_front();
+ return t;
+ }
+
+ // Removes and returns item from back of Queue
+ T pop_back()
+ {
+ std::scoped_lock lock(muxQueue);
+ auto t = std::move(deqQueue.back());
+ deqQueue.pop_back();
+ return t;
+ }
+
+ // Adds an item to back of Queue
+ void push_back(const T& item)
+ {
+ std::scoped_lock lock(muxQueue);
+ deqQueue.emplace_back(std::move(item));
+
+ std::unique_lock ul(muxBlocking);
+ cvBlocking.notify_one();
+ }
+
+ // Adds an item to front of Queue
+ void push_front(const T& item)
+ {
+ std::scoped_lock lock(muxQueue);
+ deqQueue.emplace_front(std::move(item));
+
+ std::unique_lock ul(muxBlocking);
+ cvBlocking.notify_one();
+ }
+
+ // Returns true if Queue has no items
+ bool empty()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.empty();
+ }
+
+ // Returns number of items in Queue
+ size_t count()
+ {
+ std::scoped_lock lock(muxQueue);
+ return deqQueue.size();
+ }
+
+ // Clears Queue
+ void clear()
+ {
+ std::scoped_lock lock(muxQueue);
+ deqQueue.clear();
+ }
+
+ void wait()
+ {
+ while (empty())
+ {
+ std::unique_lock ul(muxBlocking);
+ cvBlocking.wait(ul);
+ }
+ }
+
+ protected:
+ std::mutex muxQueue;
+ std::deque deqQueue;
+ std::condition_variable cvBlocking;
+ std::mutex muxBlocking;
+ };
+}
diff --git a/ClientSimulation/AsioNetClientServer/src/net_message.h b/ClientSimulation/AsioNetClientServer/src/net_message.h
new file mode 100644
index 0000000..c332573
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/src/net_message.h
@@ -0,0 +1,214 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, �OneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+#include "net_common.h"
+#include
+namespace net
+{
+ ///[OLC_HEADERIFYIER] START "MESSAGE"
+
+ // Message Header is sent at start of all messages. The template allows us
+ // to use "enum class" to ensure that the messages are valid at compile time
+ template
+ struct MessageHeader
+ {
+ T id{};
+ uint32_t size = 0;
+ };
+
+ // Message Body contains a header and a std::vector, containing raw bytes
+ // of infomation. This way the message can be variable length, but the size
+ // in the header must be updated.
+ template
+ struct Message
+ {
+ // Header & Body vector
+ MessageHeader header{};
+ std::vector body;
+
+
+ // returns size of entire message packet in bytes
+ size_t size() const
+ {
+ return body.size();
+ }
+
+ // Override for std::cout compatibility - produces friendly description of message
+ friend std::ostream& operator << (std::ostream& os, const Message& msg)
+ {
+ os << "ID:" << int(msg.header.id) << " Size:" << msg.header.size;
+ return os;
+ }
+
+ // Convenience Operator overloads - These allow us to add and remove stuff from
+ // the body vector as if it were a stack, so First in, Last Out. These are a
+ // template in itself, because we dont know what data type the user is pushing or
+ // popping, so lets allow them all. NOTE: It assumes the data type is fundamentally
+ // Plain Old Data (POD). TLDR: Serialise & Deserialise into/from a vector
+
+ // Pushes any POD-like data into the message buffer
+ template
+ friend Message& operator << (Message& msg, const DataType& data)
+ {
+ // Check that the type of the data being pushed is trivially copyable
+ static_assert(std::is_standard_layout::value, "Data is too complex to be pushed into vector");
+
+ // Cache current size of vector, as this will be the point we insert the data
+ size_t i = msg.body.size();
+
+ // Resize the vector by the size of the data being pushed
+ msg.body.resize(i + sizeof(DataType));
+
+ // Physically copy the data into the newly allocated vector space
+ std::memcpy(msg.body.data() + i, &data, sizeof(DataType));
+
+ // Recalculate the message size
+ msg.header.size = msg.size();
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ //Specified template to write string
+ friend Message& operator << (Message& msg, const std::string& data)
+ {
+ // Cache current size of vector, as this will be the point we insert the data
+ size_t i = msg.body.size();
+
+ // Resize the vector by the size of the data being pushed
+ //msg.body.resize(i + sizeof(data));
+
+ // Physically copy the data of the string character by character
+ msg.body.resize(i + data.size());
+
+ for (size_t index = 0; index < data.size(); index++) {
+ msg.body[i+index] = data.at(index);
+ //std::memcpy(msg.body.data() + i, &c, sizeof(uint8_t));
+ }
+
+ // Recalculate the message size
+ msg.header.size = (uint32_t)msg.size();
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ // Pulls any POD-like data form the message buffer
+ template
+ friend Message& operator >> (Message& msg, DataType& data)
+ {
+ // Check that the type of the data being pushed is trivially copyable
+ static_assert(std::is_standard_layout::value, "Data is too complex to be pulled from vector");
+
+ // Cache the location towards the end of the vector where the pulled data starts
+ size_t i = msg.body.size() - sizeof(DataType);
+
+ // Physically copy the data from the vector into the user variable
+ std::memcpy(&data, msg.body.data() + i, sizeof(DataType));
+
+ // Shrink the vector to remove read bytes, and reset end position
+ msg.body.resize(i);
+
+ // Recalculate the message size
+ msg.header.size = msg.size();
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ //Specified template to read string
+ friend Message& operator >> (Message& msg, std::string& data)
+ {
+ // Cache the location towards the end of the vector where the pulled data starts
+ size_t i = 0;
+
+ // Physically copy the data from the vector into the user variable
+ std::memcpy(&data, msg.body.data(), msg.body.size());
+
+ // Shrink the vector to remove read bytes, and reset end position
+ msg.body.resize(i);
+
+ // Return the target message so it can be "chained"
+ return msg;
+ }
+
+ };
+
+
+ // An "owned" message is identical to a regular message, but it is associated with
+ // a connection. On a server, the owner would be the client that sent the message,
+ // on a client the owner would be the server.
+
+ // Forward declare the connection
+ template
+ class Connection;
+
+ template
+ struct OwnedMessage
+ {
+ std::shared_ptr> remote = nullptr;
+ Message msg;
+
+ // Again, a friendly string maker
+ friend std::ostream& operator<<(std::ostream& os, const OwnedMessage& msg)
+ {
+ os << msg.msg;
+ return os;
+ }
+ };
+
+}
diff --git a/ClientSimulation/AsioNetClientServer/src/net_server.h b/ClientSimulation/AsioNetClientServer/src/net_server.h
new file mode 100644
index 0000000..3559a2c
--- /dev/null
+++ b/ClientSimulation/AsioNetClientServer/src/net_server.h
@@ -0,0 +1,279 @@
+/*
+ MMO Client/Server Framework using ASIO
+ "Happy Birthday Mrs Javidx9!" - javidx9
+
+ Videos:
+ Part #1: https://youtu.be/2hNdkYInj4g
+ Part #2: https://youtu.be/UbjxGvrDrbw
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2020 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions or derivations of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce
+ the above copyright notice. This list of conditions and the following
+ disclaimer must be reproduced in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, ?OneLoneCoder 2019, 2020
+
+*/
+
+#pragma once
+#include "net_dequeue_ts.h"
+#include "net_common.h"
+#include "net_message.h"
+#include "net_connection.h"
+#include "easylogging++.h"
+
+namespace net
+{
+ template
+ class ServerInterface
+ {
+ public: // Create a server, ready to listen on specified port
+ ServerInterface(uint16_t port)
+ : m_asioAcceptor(m_asioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) { }
+
+ virtual ~ServerInterface() { Stop(); }
+
+ // Starts the server
+ virtual bool Start()
+ {
+ try
+ {
+ // Issue a task to the asio context - This is important
+ // as it will prime the context with "work", and stop it
+ // from exiting immediately. Since this is a server, we
+ // want it primed ready to handle clients trying to
+ // connect.
+ WaitForClientConnection();
+ // Launch the asio context in its own thread
+ m_threadContext = std::thread([this]() { m_asioContext.run(); });
+ }
+ catch (std::exception& e)
+ {
+ // Something prohibited the server from listening
+ std::cerr << "[SERVER] Exception: " << e.what() << "\n";
+ return false;
+ }
+
+ LOG(INFO) << "[SERVER] Started\n";
+ return true;
+ }
+
+ bool isStopped()const {
+ return m_asioContext.stopped();
+ }
+
+ // Stops the server!
+ virtual void Stop()
+ {
+ // Request the context to close
+ m_asioContext.stop();
+
+ // Tidy up the context thread
+ if (m_threadContext.joinable()) m_threadContext.join();
+
+ // Inform someone, anybody, if they care...
+ LOG(INFO) << "[SERVER] Stopped!\n";
+ }
+
+ // ASYNC - Instruct asio to wait for connection
+ void WaitForClientConnection()
+ {
+ // Prime context with an instruction to wait until a socket connects. This
+ // is the purpose of an "acceptor" object. It will provide a unique socket
+ // for each incoming connection attempt
+ m_asioAcceptor.async_accept(
+ [this](std::error_code ec, asio::ip::tcp::socket socket)
+ {
+ // Triggered by incoming connection request
+ if (!ec)
+ {
+ LOG(INFO) << "[SERVER] New Connection: " << socket.remote_endpoint();
+
+ // Create a new connection to handle this client
+ std::shared_ptr> newconn =
+ std::make_shared>(Connection::Owner::SERVER,
+ m_asioContext, std::move(socket), m_qMessagesIn);
+
+
+ // Give the user server a chance to deny connection
+ if (OnClientConnect(newconn))
+ {
+ // Connection allowed, so add to container of new connections
+ m_deqConnections.push_back(std::move(newconn));
+
+ // Issue a task to the connection's
+ // asio context to sit and wait for bytes to arrive!
+ m_deqConnections.back()->ConnectToClient(nIDCounter++);
+
+ LOG(INFO) << "[" << m_deqConnections.back()->GetID() << "] Connection Approved\n";
+ }
+ else
+ {
+ LOG(INFO) << "[SERVER] Connection Denied";
+
+ // Connection will go out of scope with no pending tasks, so will
+ // get destroyed automatically (smart pointer)
+ }
+ }
+ else
+ {
+ // Error has occurred during acceptance
+ LOG(INFO) << "[SERVER] New Connection Error: " << ec.message();
+ }
+
+ // Prime the asio context with more work - again simply wait for
+ // another connection...
+ WaitForClientConnection();
+ });
+ }
+
+ // Send a message to a specific client
+ void MessageClient(std::shared_ptr> client, const Message& msg)
+ {
+ // Check client is legitimate...
+ if (client && client->IsConnected())
+ {
+ // ...and post the message via the connection
+ client->Send(msg);
+ }
+ else
+ {
+ // If we cant communicate with client then we may as
+ // well remove the client - let the server know, it may
+ // be tracking it somehow
+ OnClientDisconnect(client);
+
+ // Off you go now, bye bye!
+ client.reset();
+
+ // Then physically remove it from the container
+ m_deqConnections.erase(
+ std::remove(m_deqConnections.begin(), m_deqConnections.end(), client), m_deqConnections.end());
+ }
+ }
+
+ // Send message to all clients
+ void MessageAllClients(const Message& msg, std::shared_ptr> pIgnoreClient = nullptr)
+ {
+ bool bInvalidClientExists = false;
+
+ // Iterate through all clients in container
+ for (auto& client : m_deqConnections)
+ {
+ // Check client is connected...
+ if (client && client->IsConnected())
+ {
+ // ..it is!
+ if(client != pIgnoreClient)
+ client->Send(msg);
+ }
+ else
+ {
+ // The client couldnt be contacted, so assume it has
+ // disconnected.
+ OnClientDisconnect(client);
+ client.reset();
+
+ // Set this flag to then remove dead clients from container
+ bInvalidClientExists = true;
+ }
+ }
+
+ // Remove dead clients, all in one go - this way, we dont invalidate the
+ // container as we iterated through it.
+ if (bInvalidClientExists)
+ m_deqConnections.erase(
+ std::remove(m_deqConnections.begin(), m_deqConnections.end(), nullptr), m_deqConnections.end());
+ }
+
+ // Force server to respond to incoming messages
+ // size_t nmaxMessages: Assign -1 to unsigned to unspecify max message count
+ // bool bWait: if queue is empty, wait synchronously until message arrives
+ void Update(size_t nMaxMessages = -1, bool bWait = false)
+ {
+ if (bWait) m_qMessagesIn.wait();
+
+ // Process as many messages as you can up to the value
+ // specified
+ size_t nMessageCount = 0;
+ while (nMessageCount < nMaxMessages && !m_qMessagesIn.empty())
+ {
+ // Grab the front message
+ auto msg = m_qMessagesIn.pop_front();
+
+ // Pass to message handler
+ OnMessage(msg.remote, msg.msg);
+
+ nMessageCount++;
+ }
+ }
+
+ protected:
+ //Overwritable functions to customize server behaviour
+
+ // Called when a client connects, you can veto the connection by returning false
+ virtual bool OnClientConnect(std::shared_ptr> client) = 0;
+ // Called when a client appears to have disconnected
+ virtual void OnClientDisconnect(std::shared_ptr> client) = 0;
+
+ // Called when a message arrives
+ virtual void OnMessage(std::shared_ptr> client, Message& msg) = 0;
+
+
+ protected:
+ // Thread Safe Queue for incoming message packets
+ ts_dequeue> m_qMessagesIn;
+
+ // Container of active validated connections
+ std::deque>> m_deqConnections;
+
+ // Order of declaration is important - it is also the order of initialisation
+ asio::io_context m_asioContext;
+ std::thread m_threadContext;
+
+ // These things need an asio context
+ asio::ip::tcp::acceptor m_asioAcceptor; // Handles new incoming connection attempts...
+
+ // Clients will be identified in the "wider system" via an ID
+ uint32_t nIDCounter = 100;
+ };
+}
diff --git a/ClientSimulation/ClientSimulation.cpp b/ClientSimulation/ClientSimulation.cpp
new file mode 100644
index 0000000..f42dbf4
--- /dev/null
+++ b/ClientSimulation/ClientSimulation.cpp
@@ -0,0 +1,197 @@
+//Simulation of an external IP-TCP client using ASIO lib
+
+#include
+#include "asio.hpp"
+#include
+#include
+#include
+#include
+#include
+#include "PublisherData.h"
+#include "DataModel.h"
+#include "IpTcpClient.h"
+#include "NetClient.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include "easylogging++.h"
+INITIALIZE_EASYLOGGINGPP
+
+constexpr unsigned int BUFFER_SIZE = 256;
+//Format of Date in the log files
+constexpr char logDateFormat[] = "%Y-%m-%d %H:%M:%S";
+constexpr unsigned short DATE_HEADER_SIZE = 19;
+const auto session_id = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count();
+using asio::ip::tcp;
+
+
+std::atomic_char keyboardInput = '0';
+
+void readInput() {
+ while (1){
+ keyboardInput = std::cin.get();
+ std::cin.get();
+ }
+}
+
+//Takes a message with log file body and extracts the last written log date
+//This values is taken for the next log file downloading, to minimize download data size
+//and prevent the aplication from downloading data twice
+long long parseDate(net::Message& msg) {
+ if (msg.header.size < DATE_HEADER_SIZE)
+ return 0;
+
+ std::stringstream ss;
+ //Find last occurence of '\n' with reverse iteration
+ auto res = std::find_if(msg.body.rbegin(), msg.body.rend(),
+ [](const uint8_t i) { return i == '\n'; });
+ if (res == msg.body.rend()) {
+ //No occurence of '\n', log file is empty
+ return 0;
+ }
+ //Find last but one occurence of '\n' using reverse iteration
+ res = std::find_if(res+1, msg.body.rend(),
+ [](const uint8_t i) { return i == '\n'; });
+ if (res == msg.body.rend()) {
+ //No second occurence of '\n'
+ //-> only one line of log, set iterator to first position
+ res = msg.body.rend();
+ }
+ //Extreact the header and parse it to proper date format
+ for (size_t i = 0; i < DATE_HEADER_SIZE; i++) {
+ ss << *(--res);
+ }
+ std::tm tm = {};
+ ss >> std::get_time(&tm, logDateFormat);
+ long long tp = std::chrono::system_clock::from_time_t(std::mktime(&tm)).time_since_epoch().count();
+
+ return tp;
+}
+
+void writeToFile(net::Message& msg) {
+ std::ofstream file;
+ std::stringstream fileName;
+ switch(msg.header.id){
+ case net::MessageTypes::ServerData:
+ fileName << "backup_data_" << session_id << ".log";
+ break;
+ case net::MessageTypes::ServerLog:
+ fileName << "backup_log_" << session_id << ".log";
+ break;
+ default: break;
+ }
+
+ file.open(fileName.str(), std::ios_base::app);
+ for (auto c : msg.body)
+ file << c;
+ file.close();
+}
+
+
+int main()
+{
+ NetClient c;
+ long long lastLog = 0;
+
+
+ LOG(INFO) << "press key to connect";
+ std::cin.get();
+
+ c.Connect("127.0.0.1", 7777);
+
+ std::thread keyboardInputThread(readInput);
+
+ bool connectionCancelled = false;
+
+ while (!connectionCancelled)
+ {
+ if (c.IsConnected())
+ {
+ if (!c.Incoming().empty())
+ {
+ auto msg = c.Incoming().pop_front().msg;
+
+ net::Message messageSend;
+ std::string buf = "";
+
+ switch (msg.header.id)
+ {
+ case net::MessageTypes::ServerAlert:
+ // Server has responded to a ping request
+ LOG(INFO) << "Server Alert notification";
+ for (size_t index = 0; index < msg.header.size; index++) {
+ buf += msg.body.at(index);
+ }
+ LOG(INFO) << buf;
+ break;
+ case net::MessageTypes::ServerAccept:
+ // Server has responded to a ping request
+ LOG(INFO) << "Server Accepted Connection";
+ break;
+ case net::MessageTypes::ServerDeny:
+ // Server has responded to a ping request
+ LOG(INFO) << "Server Denied Connection";
+ connectionCancelled = true;
+ break;
+ case net::MessageTypes::ServerLog:
+ // Server has send log data
+ LOG(INFO) << "Received Server Log File";
+ LOG(INFO) << "Received " << msg.header.size << " Bytes";
+ writeToFile(msg);
+ lastLog = parseDate(msg);
+ break;
+ case net::MessageTypes::ServerData:
+ LOG(INFO) << "Received Server Data";
+ LOG(INFO) << "Received " << msg.header.size << " Bytes";
+ writeToFile(msg);
+
+ break;
+ default: break;
+ }
+ }
+ if (keyboardInput != '0') {
+ net::Message messageSend;
+
+ switch (keyboardInput)
+ {
+ //Log
+ case 'l':
+ LOG(INFO) << "Request server log files";
+ messageSend.header.id = net::MessageTypes::ServerLog;
+ messageSend << lastLog;
+ c.Send(messageSend);
+ break;
+ case 'd':
+ LOG(INFO) << "Request permanent server data";
+ messageSend.header.id = net::MessageTypes::ServerData;
+ c.Send(messageSend);
+ break;
+ case 't':
+ LOG(INFO) << "Request temporary server data";
+ messageSend.header.id = net::MessageTypes::ServerData;
+ c.Send(messageSend);
+ break;
+ case 'c':
+ LOG(INFO) << "Request closing connection";
+ messageSend.header.id = net::MessageTypes::ServerCloseConnection;
+ c.Send(messageSend);
+ break;
+ default:
+ break;
+ }
+ keyboardInput = '0';
+ }
+ }
+ else
+ {
+ LOG(INFO) << "Server Down";
+ break;
+ }
+ }
+ LOG(INFO) << "End excution";
+
+ return 0;
+}
diff --git a/ClientSimulation/ClientSimulation.pro b/ClientSimulation/ClientSimulation.pro
new file mode 100644
index 0000000..1888153
--- /dev/null
+++ b/ClientSimulation/ClientSimulation.pro
@@ -0,0 +1,34 @@
+TEMPLATE = app
+CONFIG += console c++17
+CONFIG -= app_bundle
+CONFIG -= qt
+
+QMAKE_CXXFLAGS += -std=c++0x -pthread
+LIBS += -pthread
+
+INCLUDEPATH += /home/michael/baConditionMonitoring/ClientSimulation/ClientSimulation/AsioNetClientServer/
+INCLUDEPATH += /home/michael/baConditionMonitoring/ClientSimulation/ClientSimulation/AsioNetClientServer/src
+
+SOURCES += \
+ ClientSimulation.cpp \
+ DataModel.cpp \
+ IpTcpClient.cpp \
+ NetClient.cpp \
+ PublisherData.cpp \
+ easylogging++.cc
+
+HEADERS += \
+ AsioNetClientServer/net_server_client.h \
+ AsioNetClientServer/src/net_client.h \
+ AsioNetClientServer/src/net_common.h \
+ AsioNetClientServer/src/net_connection.h \
+ AsioNetClientServer/src/net_dequeue_ts.h \
+ AsioNetClientServer/src/net_message.h \
+ AsioNetClientServer/src/net_server.h \
+ DataModel.h \
+ IpTcpClient.h \
+ NetClient.h \
+ PublisherData.h \
+ PublisherType.h \
+ easylogging++.h \
+ instreamOperator.h
diff --git a/ClientSimulation/ClientSimulation.pro.user b/ClientSimulation/ClientSimulation.pro.user
new file mode 100644
index 0000000..738e6b4
--- /dev/null
+++ b/ClientSimulation/ClientSimulation.pro.user
@@ -0,0 +1,355 @@
+
+
+
+
+
+ EnvironmentId
+ {5a632e4a-e744-412b-acc7-3b951573dab3}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ Builtin.Questionable
+
+ true
+ Builtin.DefaultTidyAndClazy
+ 1
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 5.15.1 GCC 64bit
+ Desktop Qt 5.15.1 GCC 64bit
+ qt.qt5.5151.gcc_64_kit
+ 0
+ 0
+ 0
+
+ true
+ 0
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Debug
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ 2
+ 2
+
+
+ true
+ 2
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Release
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 2
+
+
+ true
+ 0
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Profile
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+
+ -e
+ cpu-cycles
+ --call-graph
+ dwarf,4096
+ -F
+ 250
+
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+ 2
+
+ Qt4ProjectManager.Qt4RunConfiguration:/home/michael/baConditionMonitoring/ClientSimulation/ClientSimulation/ClientSimulation.pro
+ /home/michael/baConditionMonitoring/ClientSimulation/ClientSimulation/ClientSimulation.pro
+
+ false
+
+ false
+ true
+ true
+ false
+ false
+ true
+
+ /home/michael/baConditionMonitoring/ClientSimulation/build-ClientSimulation-Desktop_Qt_5_15_1_GCC_64bit-Debug
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/ClientSimulation/DataModel.cpp b/ClientSimulation/DataModel.cpp
new file mode 100644
index 0000000..992b977
--- /dev/null
+++ b/ClientSimulation/DataModel.cpp
@@ -0,0 +1,103 @@
+#include "DataModel.h"
+#include "instreamOperator.h"
+#include
+#include
+#include
+#include
+#include
+
+
+//Initialization of static member
+std::unique_ptr DataModel::instance = nullptr;
+
+//Read file locker
+std::timed_mutex accessFilesMTX;
+
+inline void DataModel::Create() {
+
+ instance = std::make_unique();
+}
+
+std::unique_ptr& DataModel::Instance() {
+ if (!instance)
+ Create();
+ return instance;
+}
+
+inline void DataModel::Destroy() {
+ if (instance)
+ instance.reset();
+}
+
+std::ostream& operator<<(std::ostream& os, const PublisherType type) {
+ switch (type) {
+ case PublisherType::RCMS_BENDER:
+ os << "Bender RCMS";
+ break;
+ case PublisherType::POWERCENTER:
+ os << "Siemens Powercenter";
+ break;
+ default:
+ os << "";
+ break;
+ }
+ return os;
+}
+
+
+void DataModel::savePublishedData(PublisherData data)
+{
+ auto iter = savedPublishedData.find(data.getID());
+ if (iter != savedPublishedData.end()) {
+ iter->second.push_back(data);
+ }
+ else {
+ std::vector test{ data };
+ savedPublishedData.emplace(data.getID(), test);
+ }
+}
+
+std::istream& operator>>(std::istream& is, char const* pat);
+
+//Deserialize dataModel object
+std::istream& operator>>(std::istream& is, DataModel& dataModel) {
+
+ char a;
+
+ //Prase header
+ unsigned long long startTime;
+ unsigned int interval;
+ is >> startTime >> "," >> interval;
+ //remove return
+ is.get();
+
+ //Parse Body
+ while (( a = is.peek()) != EOF) {
+ unsigned int id;
+ is >> id >> ":";
+ try {
+ std::vector values;
+ while (is.peek() != '\n') {
+ PublisherData data;
+ is >> data;
+ data.setID(id);
+ values.push_back(data);
+ }
+ is.get();
+
+ auto iter = dataModel.savedPublishedData.find(id);
+ if (iter == dataModel.savedPublishedData.end()) {
+ dataModel.savedPublishedData.emplace(id, values);
+ }
+ else {
+ for (auto& v : values)
+ {
+ iter->second.push_back(v);
+ }
+ }
+ }
+ catch (std::exception& e) { std::cout << e.what(); }
+ }
+
+ return is;
+}
\ No newline at end of file
diff --git a/ClientSimulation/DataModel.h b/ClientSimulation/DataModel.h
new file mode 100644
index 0000000..9262ffb
--- /dev/null
+++ b/ClientSimulation/DataModel.h
@@ -0,0 +1,43 @@
+#pragma once
+#include
+#include
+#include