ClientServerProject/server.h

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)){}
};