Moved UDP logic from Hybrid server/client to UDP server/client. fixed bug in Server::CheckForTimeOuts.

This commit is contained in:
Jocke
2016-02-08 14:32:00 +01:00
parent 88d7b79cd3
commit ba9419b342
16 changed files with 271 additions and 230 deletions
+2 -14
View File
@@ -1,25 +1,13 @@
#ifndef HybridClient_h__ #ifndef HybridClient_h__
#define HybridClient_h__ #define HybridClient_h__
#include "Client.h" class HybridClient
class HybridClient : public Client
{ {
public: public:
HybridClient(ConfigFile* config); HybridClient();
~HybridClient(); ~HybridClient();
void Start(World* world, EventBroker* eventBroker);
private: private:
// Assio UDP logic
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
boost::asio::io_service m_IOService;
boost::asio::ip::udp::socket m_Socket;
void connect();
void readFromServer();
int receive(char * data);
void send(Packet & packet);
}; };
#endif #endif
+1 -14
View File
@@ -1,25 +1,12 @@
#ifndef HybridServer_h__ #ifndef HybridServer_h__
#define HybridServer_h__ #define HybridServer_h__
#include "Server.h" class HybridServer
#include <boost/asio/ip/udp.hpp>
class HybridServer : public Server
{ {
public: public:
HybridServer(); HybridServer();
~HybridServer(); ~HybridServer();
private: private:
// UDP logic
boost::asio::io_service m_IOService;
std::unique_ptr<boost::asio::ip::udp::socket> m_Socket;
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
void readFromClients();
void parseConnect(Packet & packet);
void send(Packet & packet, PlayerDefinition & playerDefinition);
void send(Packet & packet);
int receive(char * data);
}; };
#endif #endif
+1 -2
View File
@@ -8,12 +8,11 @@ class TCPClient : public Client
public: public:
TCPClient(ConfigFile* config); TCPClient(ConfigFile* config);
~TCPClient(); ~TCPClient();
void Start(World* world, EventBroker* eventBroker);
private: private:
// Assio TCP logic // Assio TCP logic
boost::asio::ip::tcp::endpoint m_Endpoint; boost::asio::ip::tcp::endpoint m_Endpoint;
boost::asio::io_service m_IOService; boost::asio::io_service m_IOService;
boost::shared_ptr<boost::asio::ip::tcp::socket> m_Socket; std::unique_ptr<boost::asio::ip::tcp::socket> m_Socket;
void connect(); void connect();
void readFromServer(); void readFromServer();
+2 -2
View File
@@ -14,13 +14,13 @@ private:
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor; std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
boost::shared_ptr<boost::asio::ip::tcp::socket> lastReceivedSocket; boost::shared_ptr<boost::asio::ip::tcp::socket> lastReceivedSocket;
void readFromClients();
void acceptNewConnections(); void acceptNewConnections();
void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::system::error_code & error); void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::system::error_code & error);
void readFromClients();
int receive(char * data, boost::asio::ip::tcp::socket& socket);
void parseConnect(Packet & packet); void parseConnect(Packet & packet);
void send(Packet & packet, PlayerDefinition & playerDefinition); void send(Packet & packet, PlayerDefinition & playerDefinition);
void send(Packet & packet); void send(Packet & packet);
int receive(char * data, boost::asio::ip::tcp::socket& socket);
}; };
#endif #endif
+24
View File
@@ -0,0 +1,24 @@
#ifndef UDPClient_h__
#define UDPClient_h__
#include "Client.h"
class UDPClient : public Client
{
public:
UDPClient(ConfigFile* config);
~UDPClient();
private:
// Assio UDP logic
boost::asio::io_service m_IOService;
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
boost::asio::ip::udp::socket m_Socket;
void connect();
void readFromServer();
int receive(char * data);
void send(Packet & packet);
};
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef UDPServer_h__
#define UDPServer_h__
#include "Server.h"
#include <boost/asio/ip/udp.hpp>
class UDPServer : public Server
{
public:
UDPServer();
~UDPServer();
private:
// UDP logic
boost::asio::io_service m_IOService;
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
std::unique_ptr<boost::asio::ip::udp::socket> m_Socket;
void readFromClients();
int receive(char * data);
void parseConnect(Packet & packet);
void send(Packet & packet, PlayerDefinition & playerDefinition);
void send(Packet & packet);
};
#endif
+5
View File
@@ -26,10 +26,15 @@
// Network // Network
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "Network/Network.h" #include "Network/Network.h"
// Hybrid
#include "Network/HybridServer.h" #include "Network/HybridServer.h"
#include "Network/HybridClient.h" #include "Network/HybridClient.h"
// TCP
#include "Network/TCPClient.h" #include "Network/TCPClient.h"
#include "Network/TCPServer.h" #include "Network/TCPServer.h"
// UDP
#include "Network/UDPServer.h"
#include "Network/UDPClient.h"
// Sound // Sound
#include "Sound/SoundSystem.h" #include "Sound/SoundSystem.h"
+2 -1
View File
@@ -17,7 +17,8 @@ Client::Client(ConfigFile* config)
} }
Client::~Client() Client::~Client()
{ } {
}
void Client::Start(World* world, EventBroker* eventBroker) void Client::Start(World* world, EventBroker* eventBroker)
{ {
+1 -63
View File
@@ -1,72 +1,10 @@
#include "Network/HybridClient.h" #include "Network/HybridClient.h"
using namespace boost::asio::ip;
HybridClient::HybridClient(ConfigFile * config) : Client(config), m_Socket(m_IOService) HybridClient::HybridClient()
{ {
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
} }
HybridClient::~HybridClient() HybridClient::~HybridClient()
{ {
}
void HybridClient::Start(World* world, EventBroker* eventBroker)
{
Client::Start(world, eventBroker);
m_Socket.connect(m_ReceiverEndpoint);
}
void HybridClient::readFromServer()
{
while (m_Socket.available()) {
bytesRead = receive(readBuffer);
if (bytesRead > 0) {
Packet packet(readBuffer, bytesRead);
parseMessageType(packet);
}
}
}
int HybridClient::receive(char* data)
{
boost::system::error_code error;
int bytesReceived = m_Socket.receive_from(boost
::asio::buffer((void*)data, BUFFERSIZE),
m_ReceiverEndpoint,
0, error);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataReceived += bytesReceived;
m_NetworkData.DataReceivedThisInterval += bytesReceived;
m_NetworkData.AmountOfMessagesReceived++;
}
if (error) {
//LOG_ERROR("receive: %s", error.message().c_str());
}
return bytesReceived;
}
void HybridClient::send(Packet& packet)
{
m_Socket.send_to(boost::asio::buffer(
packet.Data(),
packet.Size()),
m_ReceiverEndpoint, 0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
m_NetworkData.AmountOfMessagesSent++;
}
}
void HybridClient::connect()
{
Packet packet(MessageType::Connect, m_SendPacketID);
packet.WriteString(m_PlayerName);
m_StartPingTime = std::clock();
send(packet);
} }
-115
View File
@@ -2,123 +2,8 @@
HybridServer::HybridServer() HybridServer::HybridServer()
{ {
m_Socket = std::unique_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)));
} }
HybridServer::~HybridServer() HybridServer::~HybridServer()
{ }
void HybridServer::readFromClients()
{ {
while (m_Socket->available()) {
try {
bytesRead = receive(readBuffer);
m_Address = m_ReceiverEndpoint.address();
m_Port = m_ReceiverEndpoint.port();
Packet packet(readBuffer, bytesRead);
parseMessageType(packet);
} catch (const std::exception& err) {
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
} }
}
std::clock_t currentTime = std::clock();
// Send snapshot
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
sendSnapshot();
previousSnapshotMessage = currentTime;
}
// Send pings each
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
sendPing();
previousePingMessage = currentTime;
}
// Time out logic
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
checkForTimeOuts();
timOutTimer = currentTime;
}
}
void HybridServer::parseConnect(Packet& packet)
{
LOG_INFO("Parsing connections");
// Check if player is already connected
if (GetPlayerIDFromEndpoint() != -1) {
return;
}
// Create a new player
PlayerDefinition pd;
pd.EntityID = 0; // Overlook this
pd.Endpoint = m_ReceiverEndpoint;
pd.Address = m_ReceiverEndpoint.address();
pd.Port = m_ReceiverEndpoint.port();
pd.Name = packet.ReadString();
pd.PacketID = 0;
pd.StopTime = std::clock();
m_ConnectedPlayers[m_NextPlayerID++] = pd;
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str());
// Send a message to the player that connected
Packet connnectPacket(MessageType::Connect, pd.PacketID);
send(connnectPacket);
// Send notification that a player has connected
Packet notificationPacket(MessageType::PlayerConnected);
broadcast(notificationPacket);
}
void HybridServer::send(Packet& packet, PlayerDefinition & playerDefinition)
{
try {
int bytesSent = m_Socket->send_to(
boost::asio::buffer(packet.Data(), packet.Size()),
playerDefinition.Endpoint,
0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
m_NetworkData.AmountOfMessagesSent++;
}
} catch (const boost::system::system_error& e) {
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
playerDefinition.Endpoint = boost::asio::ip::udp::endpoint();
}
}
// Send back to endpoint of received packet
void HybridServer::send(Packet & packet)
{
m_Socket->send_to(
boost::asio::buffer(
packet.Data(),
packet.Size()),
m_ReceiverEndpoint,
0);
if (isReadingData) {
// Network Debug data
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
}
}
int HybridServer::receive(char * data)
{
unsigned int length = m_Socket->receive_from(
boost::asio::buffer((void*)data
, BUFFERSIZE)
, m_ReceiverEndpoint, 0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataReceived += length;
m_NetworkData.DataReceivedThisInterval += length;
m_NetworkData.AmountOfMessagesReceived++;
}
return length;
}
+5 -2
View File
@@ -9,7 +9,6 @@ Server::Server()
} }
Server::~Server() Server::~Server()
{ {
} }
void Server::Start(World* world, EventBroker* eventBroker) void Server::Start(World* world, EventBroker* eventBroker)
{ {
@@ -154,16 +153,20 @@ void Server::checkForTimeOuts()
int startPing = 1000 * m_StartPingTime int startPing = 1000 * m_StartPingTime
/ static_cast<double>(CLOCKS_PER_SEC); / static_cast<double>(CLOCKS_PER_SEC);
std::vector<PlayerID> playersToRemove;
for (auto& kv : m_ConnectedPlayers) { for (auto& kv : m_ConnectedPlayers) {
if (kv.second.Address != boost::asio::ip::address()) { if (kv.second.Address != boost::asio::ip::address()) {
int stopPing = 1000 * kv.second.StopTime / int stopPing = 1000 * kv.second.StopTime /
static_cast<double>(CLOCKS_PER_SEC); static_cast<double>(CLOCKS_PER_SEC);
if (startPing > stopPing + m_TimeoutMs) { if (startPing > stopPing + m_TimeoutMs) {
LOG_INFO("User %i timed out!", kv.second.Name); LOG_INFO("User %i timed out!", kv.second.Name);
disconnect(kv.first); playersToRemove.push_back(kv.first);
} }
} }
} }
for (size_t i = 0; i < playersToRemove.size(); i++) {
disconnect(playersToRemove.at(i));
}
} }
void Server::parseDisconnect() void Server::parseDisconnect()
+4 -7
View File
@@ -5,7 +5,7 @@ using namespace boost::asio::ip;
TCPClient::TCPClient(ConfigFile * config) : Client(config) TCPClient::TCPClient(ConfigFile * config) : Client(config)
{ {
m_Endpoint = tcp::endpoint(boost::asio::ip::address::from_string(address), port); m_Endpoint = tcp::endpoint(boost::asio::ip::address::from_string(address), port);
m_Socket = boost::shared_ptr<tcp::socket>(new tcp::socket(m_IOService, m_Endpoint)); m_Socket = std::unique_ptr<tcp::socket>(new tcp::socket(m_IOService, m_Endpoint));
tcp::no_delay option(true); tcp::no_delay option(true);
m_Socket->set_option(option); m_Socket->set_option(option);
} }
@@ -15,10 +15,6 @@ TCPClient::~TCPClient()
} }
void TCPClient::Start(World * world, EventBroker * eventBroker)
{
Client::Start(world, eventBroker);
}
void TCPClient::connect() void TCPClient::connect()
{ {
if (!m_IsConnected) { if (!m_IsConnected) {
@@ -34,7 +30,7 @@ void TCPClient::connect()
} }
} }
} }
// TODO FIX CRASH TCP CLIENT SEVER DISCONNECTS FIRST
void TCPClient::readFromServer() void TCPClient::readFromServer()
{ {
while (m_Socket->available()) { while (m_Socket->available()) {
@@ -73,9 +69,10 @@ int TCPClient::receive(char * data)
void TCPClient::send(Packet & packet) void TCPClient::send(Packet & packet)
{ {
packet.UpdateSize(); packet.UpdateSize();
boost::system::error_code error;
m_Socket->send(boost::asio::buffer( m_Socket->send(boost::asio::buffer(
packet.Data(), packet.Data(),
packet.Size())); packet.Size()), 0, error);
// Network Debug data // Network Debug data
if (isReadingData) { if (isReadingData) {
m_NetworkData.TotalDataSent += packet.Size(); m_NetworkData.TotalDataSent += packet.Size();
-2
View File
@@ -8,7 +8,6 @@ TCPServer::TCPServer()
TCPServer::~TCPServer() TCPServer::~TCPServer()
{ {
} }
void TCPServer::readFromClients() void TCPServer::readFromClients()
@@ -135,7 +134,6 @@ void TCPServer::send(Packet & packet)
} }
} }
//boost::shared_ptr<boost::asio::ip::tcp::socket> socket
int TCPServer::receive(char * data, boost::asio::ip::tcp::socket& socket) int TCPServer::receive(char * data, boost::asio::ip::tcp::socket& socket)
{ {
boost::system::error_code error; boost::system::error_code error;
+66
View File
@@ -0,0 +1,66 @@
#include "Network/UDPClient.h"
using namespace boost::asio::ip;
UDPClient::UDPClient(ConfigFile * config) : Client(config), m_Socket(m_IOService)
{
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
m_Socket.connect(m_ReceiverEndpoint);
}
UDPClient::~UDPClient()
{
}
void UDPClient::readFromServer()
{
while (m_Socket.available()) {
bytesRead = receive(readBuffer);
if (bytesRead > 0) {
Packet packet(readBuffer, bytesRead);
parseMessageType(packet);
}
}
}
int UDPClient::receive(char* data)
{
boost::system::error_code error;
int bytesReceived = m_Socket.receive_from(boost
::asio::buffer((void*)data, BUFFERSIZE),
m_ReceiverEndpoint,
0, error);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataReceived += bytesReceived;
m_NetworkData.DataReceivedThisInterval += bytesReceived;
m_NetworkData.AmountOfMessagesReceived++;
}
if (error) {
//LOG_ERROR("receive: %s", error.message().c_str());
}
return bytesReceived;
}
void UDPClient::send(Packet& packet)
{
m_Socket.send_to(boost::asio::buffer(
packet.Data(),
packet.Size()),
m_ReceiverEndpoint, 0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
m_NetworkData.AmountOfMessagesSent++;
}
}
void UDPClient::connect()
{
Packet packet(MessageType::Connect, m_SendPacketID);
packet.WriteString(m_PlayerName);
m_StartPingTime = std::clock();
send(packet);
}
+123
View File
@@ -0,0 +1,123 @@
#include "Network/UDPServer.h"
UDPServer::UDPServer()
{
m_Socket = std::unique_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)));
}
UDPServer::~UDPServer()
{
}
void UDPServer::readFromClients()
{
while (m_Socket->available()) {
try {
bytesRead = receive(readBuffer);
m_Address = m_ReceiverEndpoint.address();
m_Port = m_ReceiverEndpoint.port();
Packet packet(readBuffer, bytesRead);
parseMessageType(packet);
} catch (const std::exception& err) {
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
}
}
std::clock_t currentTime = std::clock();
// Send snapshot
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
sendSnapshot();
previousSnapshotMessage = currentTime;
}
// Send pings each
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
sendPing();
previousePingMessage = currentTime;
}
// Time out logic
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
checkForTimeOuts();
timOutTimer = currentTime;
}
}
void UDPServer::parseConnect(Packet& packet)
{
LOG_INFO("Parsing connections");
// Check if player is already connected
if (GetPlayerIDFromEndpoint() != -1) {
return;
}
// Create a new player
PlayerDefinition pd;
pd.EntityID = 0; // Overlook this
pd.Endpoint = m_ReceiverEndpoint;
pd.Address = m_ReceiverEndpoint.address();
pd.Port = m_ReceiverEndpoint.port();
pd.Name = packet.ReadString();
pd.PacketID = 0;
pd.StopTime = std::clock();
m_ConnectedPlayers[m_NextPlayerID++] = pd;
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str());
// Send a message to the player that connected
Packet connnectPacket(MessageType::Connect, pd.PacketID);
send(connnectPacket);
// Send notification that a player has connected
Packet notificationPacket(MessageType::PlayerConnected);
broadcast(notificationPacket);
}
void UDPServer::send(Packet& packet, PlayerDefinition & playerDefinition)
{
try {
int bytesSent = m_Socket->send_to(
boost::asio::buffer(packet.Data(), packet.Size()),
playerDefinition.Endpoint,
0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
m_NetworkData.AmountOfMessagesSent++;
}
} catch (const boost::system::system_error& e) {
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
playerDefinition.Endpoint = boost::asio::ip::udp::endpoint();
}
}
// Send back to endpoint of received packet
void UDPServer::send(Packet & packet)
{
m_Socket->send_to(
boost::asio::buffer(
packet.Data(),
packet.Size()),
m_ReceiverEndpoint,
0);
if (isReadingData) {
// Network Debug data
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
}
}
int UDPServer::receive(char * data)
{
unsigned int length = m_Socket->receive_from(
boost::asio::buffer((void*)data
, BUFFERSIZE)
, m_ReceiverEndpoint, 0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataReceived += length;
m_NetworkData.DataReceivedThisInterval += length;
m_NetworkData.AmountOfMessagesReceived++;
}
return length;
}
+4 -2
View File
@@ -181,13 +181,15 @@ void Game::networkFunction()
bool isServer = m_Config->Get<bool>("Networking.IsServer", false); bool isServer = m_Config->Get<bool>("Networking.IsServer", false);
if (!isServer) { if (!isServer) {
m_IsClientOrServer = true; m_IsClientOrServer = true;
m_ClientOrServer = new UDPClient(m_Config);
//m_ClientOrServer = new TCPClient(m_Config); //m_ClientOrServer = new TCPClient(m_Config);
m_ClientOrServer = new HybridClient(m_Config); //m_ClientOrServer = new HybridClient(m_Config);
} }
if (isServer) { if (isServer) {
m_IsClientOrServer = true; m_IsClientOrServer = true;
m_ClientOrServer = new UDPServer();
// m_ClientOrServer = new TCPServer(); // m_ClientOrServer = new TCPServer();
m_ClientOrServer = new HybridServer(); //m_ClientOrServer = new HybridServer();
} }
m_ClientOrServer->Start(m_World, m_EventBroker); m_ClientOrServer->Start(m_World, m_EventBroker);