Added Connection Codes

Private methods dont have capital letters and are words are separated by underscores
Added id's to TcpClient's class
Removed ptr from TcpClient and Server
Worked on TcpServer
Theres now a default server port
Added ReceiveMessage function to TcpClient to receive only 1 message
Fixed VoidNetClientAPI Receive function
This commit is contained in:
xX-TheDoctor-Xx
2016-07-22 00:32:53 +01:00
parent 1c9a9c809b
commit 6fa7872a6d
17 changed files with 353 additions and 41 deletions

View File

@ -53,12 +53,12 @@ const NetworkBuffer &NetworkMessage::EncodeMessage(const NetworkMessage &message
const NetworkMessage &NetworkMessage::DecodeMessage(const NetworkBuffer &buffer)
{
NetworkMessage message = DecodeMessageHeader(buffer);
message.data = DecodeMessageData(buffer);
NetworkMessage message = decode_message_header(buffer);
message.data = decode_message_data(buffer);
return message;
}
void *NetworkMessage::DecodeMessageData(const NetworkBuffer &buffer)
void *NetworkMessage::decode_message_data(const NetworkBuffer &buffer)
{
if (buffer.body_size < 9)
return nullptr;
@ -78,7 +78,7 @@ void *NetworkMessage::DecodeMessageData(const NetworkBuffer &buffer)
}
}
const NetworkMessage &NetworkMessage::DecodeMessageHeader(const NetworkBuffer &buffer)
const NetworkMessage &NetworkMessage::decode_message_header(const NetworkBuffer &buffer)
{
sender = Utility::BitConverter::ToUint16(buffer.body, 1);
distribution_mode = buffer.body[3];

View File

@ -10,7 +10,7 @@
#undef SendMessage
bool TcpClient::Initialize(const std::string &ip, uint16 port)
bool TcpClient::initialize(const std::string &ip, uint16 port)
{
if (ip.size() == 0 || std::count(ip.begin(), ip.end(), '.') != 4)
return false;
@ -30,8 +30,7 @@ bool TcpClient::Initialize(const std::string &ip, uint16 port)
return false;
}
ptr = result;
tcp_socket = ::socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
tcp_socket = ::socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (tcp_socket == INVALID_SOCKET)
{
@ -42,17 +41,23 @@ bool TcpClient::Initialize(const std::string &ip, uint16 port)
return false;
}
initialized = true;
return true;
return initialized = true;
}
TcpClient::TcpClient() : port(default_port)
TcpClient::TcpClient(const SOCKET & socket)
{
tcp_socket = socket;
}
TcpClient::TcpClient(const std::string &ip) : port(default_client_port)
{
initialize(ip);
}
TcpClient::TcpClient(const std::string &ip, uint16 port) :
ip(ip), port(port)
{
initialize(ip, port);
}
TcpClient::~TcpClient()
@ -60,7 +65,6 @@ TcpClient::~TcpClient()
freeaddrinfo(result);
WSACleanup();
Utility::Delete(result);
Utility::Delete(ptr);
}
const std::string &TcpClient::GetIP()
@ -83,6 +87,16 @@ void TcpClient::SetPort(uint16 port)
this->port = port;
}
uint16 TcpClient::GetID()
{
return id;
}
void TcpClient::SetID(uint16 id)
{
this->id = id;
}
bool TcpClient::Connect()
{
if (!initialized)
@ -91,17 +105,17 @@ bool TcpClient::Connect()
return false;
if (port == 0)
return false;
if (Initialize(ip, port) != true)
if (initialize(ip, port) != true)
return false;
}
uint16 connect_code = ::connect(tcp_socket, ptr->ai_addr, ptr->ai_addrlen);
uint16 connect_code = ::connect(tcp_socket, result->ai_addr, result->ai_addrlen);
if (connect_code == SOCKET_ERROR)
return false;
receive = true;
return true;
}
const NetworkBuffer &TcpClient::ReceiveDataArray()
const NetworkBuffer &TcpClient::receive_data_array()
{
NetworkBuffer buffer;
@ -122,11 +136,11 @@ const NetworkBuffer &TcpClient::ReceiveDataArray()
return buffer;
}
void TcpClient::ReceiveData(TcpClient *client)
void TcpClient::receive_data(TcpClient *client)
{
while (client->receive)
{
NetworkMessage message(client->ReceiveDataArray());
NetworkMessage message(client->receive_data_array());
if (message.valid)
{
if (message.tag == CONNECT) // some user has connected
@ -141,10 +155,15 @@ void TcpClient::ReceiveData(TcpClient *client)
void TcpClient::ReceiveMessages()
{
std::async(std::launch::async, &ReceiveData, this);
std::async(std::launch::async, &receive_data, this);
}
void TcpClient::SendNetworkMessage(const NetworkMessage &message, TcpClient *client)
const NetworkMessage & TcpClient::ReceiveMessage()
{
return receive_data_array();
}
void TcpClient::send_network_message(const NetworkMessage &message, TcpClient *client)
{
NetworkBuffer buffer = message.EncodeMessage(message);
int32 bytes_sent = send(client->tcp_socket, reinterpret_cast<char*>(buffer.body), buffer.body_size, 0);
@ -156,5 +175,5 @@ void TcpClient::SendNetworkMessage(const NetworkMessage &message, TcpClient *cli
void TcpClient::SendMessage(const NetworkMessage &message)
{
std::async(std::launch::async, &SendNetworkMessage, message, this);
}
std::async(std::launch::async, &send_network_message, message, this);
}

View File

@ -1 +1,231 @@
#include "TcpClient.hpp"
#include "TcpServer.hpp"
#include "Config.hpp"
#include "Utility.hpp"
#include <string>
#include <iostream>
#include <future>
#undef SendMessage
bool TcpServer::initialize(uint16 port)
{
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
uint16 code = getaddrinfo(0, std::to_string(port).c_str(), &hints, &result);
if (code != 0)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
WSACleanup();
return false;
}
socket = ::socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (socket == INVALID_SOCKET)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
freeaddrinfo(result);
WSACleanup();
return false;
}
code = bind(socket, result->ai_addr, result->ai_addrlen);
if (code == SOCKET_ERROR)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
freeaddrinfo(result);
closesocket(socket);
WSACleanup();
return false;
}
freeaddrinfo(result);
return initialized = true;
}
TcpServer::TcpServer()
{
initialize(); // initialize with the default port
}
TcpServer::TcpServer(uint16 port)
{
initialize(port);
}
TcpServer::~TcpServer()
{
freeaddrinfo(result);
WSACleanup();
Utility::Delete(result);
}
bool TcpServer::StartServer(bool accept_connections)
{
if (listen(socket, SOMAXCONN) == SOCKET_ERROR)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl;
closesocket(socket);
WSACleanup();
return false;
}
if (accept_connections)
AcceptConnections();
return true;
}
void TcpServer::AcceptConnections()
{
running = true;
std::async(std::launch::async, &accept_connections, this);
}
void TcpServer::accept_connections(TcpServer *server)
{
std::async(std::launch::async, &process_client_received_data, server);
while (server->running)
{
SOCKET client_socket = accept(server->socket, 0, 0);
if (client_socket == INVALID_SOCKET)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl;
closesocket(server->socket);
WSACleanup();
server->running = false;
break;
}
server->AddToClientsList(TcpClient(client_socket));
}
}
void TcpServer::process_client_received_data(TcpServer *server)
{
while (server->running) // we only process the data if we are receiving connections,
{
for (std::vector<TcpClient>::iterator it = server->clients.begin(); it != server->clients.end(); ++it)
{
TcpClient client = *it;
NetworkMessage message(client.ReceiveMessage());
std::async(std::launch::async, &process_message, server, message); // we start an async task so that we dont bottleneck the receiver
}
}
}
void TcpServer::process_message(TcpServer * server, const NetworkMessage & message)
{
if (message.valid)
server->SendMessage(message);
}
void TcpServer::SendMessage(const NetworkMessage & message)
{
switch (message.distribution_mode)
{
case All: // this will send the message to all except the user that sent it
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (message.sender != client.GetID())
client.SendMessage(message);
}
OnMessage(message);
break;
}
case AllAndMe: // this will send the message to EVERYONE including the user that sent it
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
client.SendMessage(message);
}
OnMessage(message);
break;
}
case Server: // this will only send the message to the server
{
OnMessage(message);
break;
}
case Others: // this will send the message to others, excluding server and the user that sent it
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
client.SendMessage(message);
}
break;
}
case ID: // this will send the message to a specific id
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (message.sender == client.GetID())
{
client.SendMessage(message);
break;
}
}
break;
}
}
}
uint16 TcpServer::AllocateID() // this function is only used in the AddToClientsList function
{
for (uint16 i = 1; i < max_connections; ++i)
{
bool flag = true;
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
if ((*it).GetID() == i)
{
flag = false;
break;
}
}
if (flag)
return i;
}
return 0;
}
void TcpServer::AddToClientsList(const TcpClient & client_socket)
{
TcpClient client(client_socket);
uint16 id = AllocateID();
if (id > 0)
{
client.SetID(id);
clients.emplace_back(client);
}
else
{
if (Config::GetUsingConsole())
std::cout << "No available ID's" << std::endl;
RejectConnection(client);
}
}
void TcpServer::RejectConnection(TcpClient &client)
{
NetworkMessage message;
message.sender = -1;
message.tag = Reject; // 0 for rejected connection
client.SendMessage(message);
}

View File

@ -2,6 +2,8 @@
#include "Utility.hpp"
#include "Tags.hpp"
#include <future>
#undef SendMessage
bool VoidNetClientAPI::Connect(const std::string &ip, uint16 port)
@ -50,11 +52,10 @@ void VoidNetClientAPI::SendMessage(byte distribution_mode, uint16 destination_id
void VoidNetClientAPI::Receive()
{
receive_thread = std::thread(ProcessAllData);
receive_thread.detach();
std::async(std::launch::async, &process_all_data);
}
void VoidNetClientAPI::ProcessAllData()
void VoidNetClientAPI::process_all_data()
{
client->ReceiveMessages();
}