Skip to content

Instantly share code, notes, and snippets.

@olevegard
Created May 17, 2015 06:52
Show Gist options
  • Save olevegard/345563b261444b9c03fa to your computer and use it in GitHub Desktop.
Save olevegard/345563b261444b9c03fa to your computer and use it in GitHub Desktop.
// NetManager - Headerphile.com
//
// A simple class that handles TCP Connections
//
// Has functionality for handling both server and client connections
// Can also be used for sending a message to all client connections,
// and retrieving a vector of newly received messages
//
#pragma once
#include <SDL2/SDL_net.h>
#include <vector>
#include "ServerTCPConnection.h"
#include "ClientTCPConnection.h"
class NetManager
{
public:
NetManager()
{
}
bool Init()
{
clientSocketSet= SDLNet_AllocSocketSet( 10 );
serverSocketSet = SDLNet_AllocSocketSet( 10 );
return true;
}
// Add a new client and try to connect to a server
bool AddClient(const std::string &ip, int32_t port)
{
std::unique_ptr<ClientTCPConnection>
clientCon( new ClientTCPConnection(ip, port) );
if (!clientCon->SetupIPAddress())
return false;
if (!clientCon->OpenConnectionToServer())
return false;
clientCon->AddToSocketSet( &clientSocketSet );
clientConnections.emplace_back(std::move(clientCon));
return true;
}
// Add server for listening for new connectios
bool AddServer(int32_t port)
{
std::unique_ptr<ServerTCPConnection>
serverCon( new ServerTCPConnection(port) );
if (!serverCon->SetupIPAddress())
return false;
if (!serverCon->OpenPortForListening())
return false;
serverCon->AddToSocketSet(&serverSocketSet);
// This is a bit tricky move-semantcs stuff.
// Basically ; we add serverCon to serverConnections (wihtou copying it)
serverConnections.emplace_back(std::move(serverCon));
return true;
}
// Send a message to all connected clients
// NOTE : Here you'd probably also want a way of sending a message to a specific client
// But this is beyond the scope of this simple implmentation
void SendToAll(const std::string &message)
{
for ( auto p = std::begin(clientConnections) ; p != std::end(clientConnections) ; ++p )
(*p)->Send(message);
}
// Return a vector of all messages received since last time
// NOTE : Here you'd probably want a more effective way of returning objects
// But this is beyond the scope of this simple implmentation
std::vector<std::string> GetAllMessages()
{
std::vector<std::string> messageListCopy = messageList;
messageList.clear();
return messageListCopy;
}
void DoUpdate()
{
std::cout << "\n===========================================\n";
TryToAcceptConnection();
CheckClientConnections();
std::cout << "===========================================\n";
SDL_Delay(50);
}
// Check if any clients has acitivy
// If so ; loop through the connections until we have checked all connections that had activity
void CheckClientConnections()
{
int32_t count = CountClientSocketsWithActivity();
std::cout << "Client activity : " << count << std::endl;
if ( count == 0 )
return;
int countChecked = 0;
for ( uint32_t i = 0 ; i < clientConnections.size() ; ++i)
{
// Check if this connectio has activity, which means it's either disconnect or has received a message
if (!clientConnections[i]->CheckForActivity())
continue;
std::string str = clientConnections[i]->ReadMessages();
messageList.push_back(str);
++countChecked;
// If we have checked all connections that had activity
if (countChecked == count)
break;
}
}
int CountServerSocketsWithActivity()
{
return SDLNet_CheckSockets( serverSocketSet, 5 );
}
int CountClientSocketsWithActivity()
{
return SDLNet_CheckSockets( clientSocketSet, 5 );
}
// (Server only)
// Try to accept a client that's trying to connect
bool TryToAcceptConnection()
{
int count = CountServerSocketsWithActivity();
std::cout << count << " servers connections with activity\n";
int countFound = 0;
for (uint32_t i = 0 ; i < serverConnections.size() ; ++i)
{
if ( countFound == count)
break;
if (!serverConnections[i]->CanAcceptConnection())
continue;
// Now we know that there is a connection waiting for us, so let's accept it!
auto newConnection
= serverConnections[i]->TryToAcceptConnection();
if (newConnection != nullptr)
{
newConnection->AddToSocketSet( &clientSocketSet );
clientConnections.emplace_back(std::move(newConnection));
}
}
return true;
}
private:
// The socket sets can be used to quickly check all connections
SDLNet_SocketSet serverSocketSet;
SDLNet_SocketSet clientSocketSet;
std::vector<std::string> messageList;
// I use unique pointers here. If you want to read more, you can check them out on my blog
// Otherwise ; just think of them as regular pointers
std::vector<std::unique_ptr<ServerTCPConnection> > serverConnections;
std::vector<std::unique_ptr<ClientTCPConnection> > clientConnections;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment