113 lines
3.5 KiB
C++
Executable File
113 lines
3.5 KiB
C++
Executable File
#pragma once
|
|
#include "modernize/sockets.h"
|
|
#include "libraries/event.h"
|
|
#include "libraries/osyncstream.h"
|
|
#include <thread>
|
|
|
|
|
|
|
|
class networked
|
|
{
|
|
protected:
|
|
SOCKET socket;
|
|
public:
|
|
explicit networked(SOCKET existing)
|
|
{
|
|
socket = existing;
|
|
}
|
|
auto disconnect() -> void
|
|
{
|
|
if (!is_valid()) return; //socket is closed.
|
|
net::closesocket(socket);
|
|
socket = INVALID_SOCKET;
|
|
}
|
|
[[nodiscard]] auto receive_message() const -> std::string { if (!is_valid()) return ""; return net::recv(socket); }
|
|
auto send_message(const std::string& message) const -> void { if (!is_valid()) return; net::send(socket, message);}
|
|
[[nodiscard]] auto is_valid() const -> bool { return socket != INVALID_SOCKET; }
|
|
};
|
|
|
|
|
|
class client : public networked
|
|
{
|
|
auto accept_message() -> void //add const later
|
|
{
|
|
while(is_valid()) /* Accept all messages */
|
|
{
|
|
auto message = receive_message();
|
|
if (message.empty() && is_valid()) //connection is closed or broken.
|
|
{
|
|
disconnect();
|
|
break;
|
|
}
|
|
message_received.execute(message);
|
|
}
|
|
}
|
|
public:
|
|
event<std::string&> message_received {};
|
|
explicit client() : networked(net::socket(AF_INET, SOCK_STREAM, 0)){}
|
|
auto connect(const std::string& ip, const port port) -> std::thread
|
|
{
|
|
const auto address = net::getaddrinfo(ip, std::to_string(port));
|
|
auto remote_address = net::getaddrinfo(ip, std::to_string(port));
|
|
if (net::connect(socket, remote_address) < 0)
|
|
return std::thread();
|
|
auto thread = std::thread(&client::accept_message, this);
|
|
return thread;
|
|
}
|
|
};
|
|
|
|
class server : networked
|
|
{
|
|
auto accept_clients() -> void
|
|
{
|
|
while(is_valid())
|
|
{
|
|
auto client = networked(accept(socket, nullptr, nullptr));
|
|
client_connected.execute(client);
|
|
#ifdef THREADED
|
|
std::thread(&server::accept_client_message, this, client).detach();
|
|
#else
|
|
std::thread(&server::accept_client_message, this, client).join();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
auto accept_client_message(networked client) -> void //add const later
|
|
{
|
|
//using namespace std::chrono_literals;
|
|
//std::this_thread::sleep_for(2000ms);
|
|
while(client.is_valid()) /* Accept all messages */
|
|
{
|
|
auto message = client.receive_message();
|
|
if (message.empty() && client.is_valid()) //Client could have disconnected after check but PRIOR to recv.
|
|
{
|
|
sscout << "Client Connection Lost\n";
|
|
client.disconnect();
|
|
break;
|
|
}
|
|
message_received.execute(client, message);
|
|
}
|
|
}
|
|
|
|
public:
|
|
event<networked&> client_connected {};
|
|
event<networked&, std::string&> message_received {};
|
|
auto listen(const std::string& ip, const port port) -> std::thread
|
|
{
|
|
const auto address = net::getaddrinfo(ip, std::to_string(port));
|
|
if (net::bind(socket, address) < 0)
|
|
{
|
|
sscout << "Error binding.\n";
|
|
return std::thread();
|
|
}
|
|
if (net::listen(socket) < 0)
|
|
{
|
|
sscout << "Error listening.\n";
|
|
return std::thread();
|
|
}
|
|
sscout << "Listening ... \n";
|
|
return std::thread(&server::accept_clients, this);
|
|
}
|
|
explicit server() : networked(net::socket(AF_INET, SOCK_STREAM, 0)){}
|
|
};
|