I am curently trying to add a multiplayer system to my game engine. To do so i decided to use the TCP approch. Since i am already using the SDL2 library i decided to use the SDL2-net library for networking.
I wish to send data to the server and vice versa. Sending small amounts of data isn't a problem however when i want to send a big chunk of data, a piece of terrain for example, the client will receiver will might get some other data mixed in between the terrain data which is of course not wanted. I am no expert in networking so there might be some basic concepts that i do not know of, and i would be more than happy to know if there is a solution to this "problem".
Thanks for your help!
In the following code a client sends a large array of numbers(in Client constructor) to a server and also a message when the client object gets destroyed(in Client destructor) but these two messages get mixed up.
Client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <SDL2/SDL_net.h>
namespace gt
{
namespace ns
{
namespace networking
{
class Client
{
private:
TCPsocket socket;
SDLNet_SocketSet socketSet;
void sendData(const char*) const;
public:
Client(const char*, int);
~Client();
void checkIncomingData();
};
}
}
}
#endif
Client.cpp
#include "Client.h"
#include <iostream>
#include <cstring>
namespace gt
{
namespace ns
{
namespace networking
{
Client::Client(const char* address, int port)
{
SDLNet_Init();
IPaddress ip;
if(SDLNet_ResolveHost(&ip, address, port) == -1)
{
std::cout << "Client connection error!" << std::endl;
}
socket = SDLNet_TCP_Open(&ip);
if(socket == NULL)
{
std::cout << "Client connection error! (wrong ip address?)" << std::endl;
}
socketSet = SDLNet_AllocSocketSet(1);
SDLNet_TCP_AddSocket(socketSet, socket);
sendData("<for the sake of simlicity i removed the numbers that were here>\n");
}
Client::~Client()
{
sendData("Client disconecting!\n");
SDLNet_TCP_Close(socket);
SDLNet_FreeSocketSet(socketSet);
SDLNet_Quit();
}
void Client::sendData(const char* data) const
{
int size = strlen(data);
int sentsize = 0;
while(sentsize < size)
{
sentsize+=SDLNet_TCP_Send(socket, data + sentsize, size - sentsize);
}
}
void Client::checkIncomingData()
{
while(SDLNet_CheckSockets(socketSet,0) > 0)
{
if(SDLNet_SocketReady(socket))
{
char data[1400];
SDLNet_TCP_Recv(socket, data, 1400);
std::cout << "data received: " << data << std::endl;
}
}
}
}
}
}
Server.h
#ifndef SERVER_H
#define SERVER_H
#include <SDL2/SDL_net.h>
#include "ClientData.h"
#include "../utils/ArrayList.h"
namespace gt
{
namespace ns
{
namespace networking
{
class Server
{
private:
int maxClients;
IPaddress ip;
TCPsocket socket;
ArrayList<ClientData> clients;
SDLNet_SocketSet clientsSet;
int currentId;
void removeClient(int);
void checkNewConnection();
void checkIncomingData();
void checkTimeouts(float);
bool readData(const TCPsocket&);
public:
Server(int, int);
~Server();
void update(float);
};
}
}
}
#endif
Server.cpp
#include "Server.h"
#include <iostream>
#include <cstring>
namespace gt
{
namespace ns
{
namespace networking
{
Server::Server(int maxClients, int port)
{
this->maxClients = maxClients;
clientsSet = SDLNet_AllocSocketSet(maxClients);
SDLNet_ResolveHost(&ip, NULL, port);
socket = SDLNet_TCP_Open(&ip);
currentId = 1;
}
Server::~Server()
{
SDLNet_FreeSocketSet(clientsSet);
SDLNet_TCP_Close(socket);
}
void Server::removeClient(int index)
{
SDLNet_TCP_DelSocket(clientsSet, clients[index].getSocket());
clients.remove(index);
}
void Server::checkNewConnection()
{
TCPsocket clientSocket = SDLNet_TCP_Accept(socket);
if(clientSocket)
{
if(clients.size() < maxClients)
{
SDLNet_TCP_AddSocket(clientsSet, clientSocket);
ClientData data(currentId, clientSocket);
clients.add(data);
std::cout << "new connection id: " << currentId << std::endl;
currentId++;
}
else
{
//no more space!
}
}
}
void Server::checkIncomingData()
{
while(SDLNet_CheckSockets(clientsSet, 0) > 0)
{
for(int i=0;i<clients.size();i++)
{
if(SDLNet_SocketReady(clients[i].getSocket()))
{
if(readData(clients[i].getSocket()))
{
clients[i].timer.reset();
}
else
{
removeClient(i);
}
}
}
}
}
void Server::checkTimeouts(float timePassed)
{
for(int i=0;i<clients.size();i++)
{
clients[i].timer.update(timePassed);
if(clients[i].timer.getTime() > 5.0)
{
removeClient(i);
}
}
}
void Server::update(float timePassed)
{
checkNewConnection();
checkIncomingData();
checkTimeouts(timePassed);
}
bool Server::readData(const TCPsocket& clientSocket)
{
char data[1400];
int size = SDLNet_TCP_Recv(clientSocket, data, 1400);
if(size <= 0)
{
std::cout << "RECEIVING DATA FAILED: " << size << std::endl;
return false;
}
std::cout << data << std::endl;
while(data[strlen(data) - 1] != '\n')
{
size = SDLNet_TCP_Recv(clientSocket, data, 1400);
if(size <= 0)
{
std::cout << "RECEIVING DATA FAILED: " << size << std::endl;
return false;
}
std::cout << data << std::endl;
}
return true;
}
}
}
}
what i get in the server terminal when i create the Client object and delete right after(the array in code is bigger i just chose the interesting part of the output):
0.1519227 -0.002553641 -0.3744464 0.1526676 0 -0.06999236 0.1529192 0.002553701 -0.06999236 0.1526677 0.005009293 -0.06999236 0.1519228 0.007272362 -0.06999236 0.1507131 0.009255945 -0.06999236 0.149085
2 0.01088386 -0.06999236 0.1471016 0.01209348 -0.06999236 0.1448385 0.01283836 -0.06999236 0.142383 0.01308989 -0.06999236 0.1398292 0.01283836 -0.06999236 0.1372755 0.01209348 -0.06999236 0.13482 0.01088386 -0.06999236 0.1325569 0.009255945 -0.06999236 0.1305733 0.007272362 -0.06999236 0.1289454 0.005009293 -0.06999236 0.1277357 0.002553701 -0.06999236 0.1269909 0 -0.06999236 0.1267393 -0.002553701 -0.06999236 0.1269909 -0.005009293 -0.06999236 0.1277357 -0.007272362 -0.06999236 0.1289454 -0.009255945 -0.06999236 0.1305733 -0.01088386 -0.06999236 0.1325569 -0.01209348 -0.06999236 0.13482 -0.01283836 -0.06999236 0.1372755 -0.01308989 -0.06999236 0.1398293 -0.01283836 -0.06999236 0.142383 -0.01209348 -0.06999236 0.1448386 -0.01088386 -0.06999236 0.1471017
.1269907 -0.005009293 -0.3744465 0.1277357 -0.007272362 -0.3744464 0.1289453 -0.009255945 -0.3744465 0.1305732 -0.01088386 -0.3744464 0.1325568 -0.01209348 -0.3744465 0.1348199 -0.01283836 -0.3744465 0.1372755 -0.01308989 -0.3744465 0.1398292 -0.01283836 -0.3744464 0.1423829 -0.01209348 -0.3744464 0.1448385 -0.01088386 -0.3744465 0.1471015 -0.009255945 -0.3744464 0.1490852 -0.007272303 -0.3744464 0.150713 -0.005009233 -0.3744464 0.1519227 -0.002553641 -0.3744464 0.1526676 0 -0.06999236 0.1529192 0.002553701 -0.06999236 0.1526677 0.005009293 -0.06999236 0.1519228 0.007272362 -0.06999236 0.1507131 0.009255945 -0.06999236 0.149085
Client disconecting! <- this message is received in the number array!
236 0.1471016 0.01209348 -0.06999236 0.1448385 0.01283836 -0.06999236 0.142383 0.01308989 -0.06999236 0.1398292 0.01283836 -0.06999236 0.1372755 0.01209348 -0.06999236 0.13482 0.01088386 -0.06999236 0.1325569 0.009255945 -0.06999236 0.1305733 0.007272362 -0.06999236 0.1289454 0.005009293 -0.06999236 0.1277357 0.002553701 -0.06999236 0.1269909 0 -0.06999236 0.1267393 -0.002553701 -0.06999236 0.1269909 -0.005009293 -0.06999236 0.1277357 -0.007272362 -0.06999236 0.1289454 -0.009255945 -0.06999236 0.1305733 -0.01088386 -0.06999236 0.1325569 -0.01209348 -0.06999236 0.13482 -0.01283836 -0.06999236 0.1372755 -0.01308989 -0.06999236 0.1398293 -0.01283836 -0.06999236 0.142383 -0.01209348 -0.06999236 0.1448386 -0.01088386 -0.06999236 0.1471017
.1269907 -0.005009293 -0.3744465 0.1277357 -0.007272362 -0.3744464 0.1289453 -0.009255945 -0.3744465 0.1305732 -0.01088386 -0.3744464 0.1325568 -0.01209348 -0.3744465 0.1348199 -0.01283836 -0.3744465 0.1372755 -0.01308989 -0.3744465 0.1398292 -0.01283836 -0.3744464 0.1423829 -0.01209348 -0.3744464 0.1448385 -0.01088386 -0.3744465 0.1471015 -0.009255945 -0.3744464 0.1490852 -0.007272303 -0.3744464 0.150713 -0.005009233 -0.3744464 0.1519227 -0.002553641 -0.3744464 0.1526676 0 -0.06999236 0.1529192 0.002553701 -0.06999236 0.1526677 0.005009293 -0.06999236 0.1519228 0.007272362 -0.06999236 0.1507131 0.009255945 -0.06999236 0.149085