I see, so using 255.255.255.255 only works on and over the local network, right?.
Could a connection over the net be done straight through an ip address, once an ip address is known?, because a master server sounds like a lot of work.
What I really want is to have the client be able to retrieve a list of servers on a local network.
The code below show how I currently plan to make the server work.
I dout the code would work yet, because I have not yet got around to debugging it, but the general ideas are still there.
The interface for the base class of the GameServer:
Code:
///////////////////////////////////////////////////////////////////////////////
// $Id$
// $Revision$
///////////////////////////////////////////////////////////////////////////////
#ifndef _SERVER_H
#define _SERVER_H
#include <list>
#include <string>
#include <stdint.h>
#include <SDL/SDL_thread.h>
#include <SDL/SDL_mutex.h>
#include "ClientSocket.h"
#include "ServerSocket.h"
// Really handy server class, if a client leaves with this server, they can
// still come back into the game while the same game is still running.
class Server {
public:
Server(uint16_t port, uint16_t maxConnections = 8);
virtual ~Server();
// Methods
virtual void Kick(uint32_t ip);
virtual void Band(uint32_t ip);
virtual void Unband(uint32_t ip);
// Events
virtual void OnRecieve(Socket* pSender, std::string const& data) = 0;
protected:
ServerSocket mServerSocket;
int mMaxConnections;
volatile bool mbAlive;
SDL_Thread** mpThreads;
std::list<Socket*> mConnections;
SDL_mutex* mpConnectionsMutex;
std::list<uint32_t> mBandConnections;
SDL_mutex* mpBandConnectionsMutex;
static int HandleClient(void* pArgs);
};
#endif // _SERVER_H
///////////////////////////////////////////////////////////////////////////////
// $Log$
///////////////////////////////////////////////////////////////////////////////
// vim:ts=2:sw=2:sts=2:et
The implementation for the base class of the GameServer:
Code:
///////////////////////////////////////////////////////////////////////////////
// $Id$
// $Revision$
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include "Server.h"
using namespace std;
//-----------------------------------------------------------------------------
int Server::HandleClient(void* _pServer)
{
try {
Server* pServer = (Server*)_pServer;
Socket client;
while (pServer->mbAlive) {
// Wait to connect to a client, if it can not connect then reloop to see
// if the server is still alive, then try again. This accept statement is
// excepted to fail serveral times due to time out errors while waiting
// for the client to be ready.
try {
pServer->mServerSocket.Accept(&client);
} catch (string const& e) {
//cout << "Server::HandleClient: " << e << endl;
continue;
}
// Make sure that this client is not already connected.
SDL_mutexP(pServer->mpConnectionsMutex);
{
list<Socket*>::const_iterator i;
for (
i = pServer->mConnections.begin();
i != pServer->mConnections.end();
++i
) {
if (client.ipAddress() == (*i)->ipAddress()) {
break;
}
}
if (i != pServer->mConnections.end()) {
client.Close();
continue;
}
}
SDL_mutexV(pServer->mpConnectionsMutex);
// Check if the client is in the band list, if so disconnect him/her and
// be ready to connect to a new client.
SDL_mutexP(pServer->mpBandConnectionsMutex);
{
uint32_t ip = client.ipAddress();
list<uint32_t>::const_iterator i;
for (
i = pServer->mBandConnections.begin();
i != pServer->mBandConnections.end();
++i
) {
if (ip == *i) {
try {
client.Close();
} catch (...) {
}
break;
}
}
if (i != pServer->mBandConnections.end()) {
continue;
}
}
SDL_mutexV(pServer->mpBandConnectionsMutex);
// Add the connected client to the list of clients.
SDL_mutexP(pServer->mpConnectionsMutex);
pServer->mConnections.push_back(&client);
SDL_mutexV(pServer->mpConnectionsMutex);
// Perform the message loop until either the client disconnects ("BYE!!!")
// or until the server is not alive (i.e. it disconnects.).
while (pServer->mbAlive) {
string data;
client.Recieve(&data);
if ((data == "BYE!!!") || (data.length() == 0)) {
break;
} else {
pServer->OnRecieve(&client, data);
}
}
// At this state the client is no longer connected to the server, so
// remove it from the connections list.
SDL_mutexP(pServer->mpConnectionsMutex);
{
list<Socket*>::iterator i;
for (
i = pServer->mConnections.begin();
i != pServer->mConnections.end();
++i
) {
if (*i == &client) {
break;
}
}
if (i != pServer->mConnections.end()) {
pServer->mConnections.erase(i);
}
}
SDL_mutexV(pServer->mpConnectionsMutex);
// Close the client.
client.Close();
}
return 0;
} catch (string const& e) {
cerr << "Server::HandleClient: " << e << endl;
return 1;
}
}
//-----------------------------------------------------------------------------
Server::Server(uint16_t port, uint16_t maxConnections):
mServerSocket(port), mMaxConnections(maxConnections), mbAlive(true),
mpThreads(new SDL_Thread*[maxConnections])
{
for (int i = 0; i < mMaxConnections; ++i) {
mpThreads[i] = 0;
}
mpConnectionsMutex = SDL_CreateMutex();
mpBandConnectionsMutex = SDL_CreateMutex();
for (int i = 0; i < mMaxConnections; ++i) {
mpThreads[i] = SDL_CreateThread(Server::HandleClient, this);
}
}
//-----------------------------------------------------------------------------
Server::~Server()
{
// Tell each of the clients that the server is shutting down.
{
list<Socket*>::iterator i;
for (i = mConnections.begin(); i != mConnections.end(); ++i) {
(*i)->Send("BYE!!!");
}
}
// Flag that the server is shutdown, and wait for the connection listening
// threads are done.
mbAlive = false;
for (int i = 0; i < mMaxConnections; ++i) {
int status;
SDL_WaitThread(mpThreads[i], &status);
}
SDL_DestroyMutex(mpConnectionsMutex);
SDL_DestroyMutex(mpBandConnectionsMutex);
delete [] mpThreads;
}
//-----------------------------------------------------------------------------
void Server::Kick(uint32_t ip)
{
SDL_mutexP(mpConnectionsMutex);
list<Socket*>::iterator i;
for (i = mConnections.begin(); i != mConnections.end(); ++i) {
if (ip == (*i)->ipAddress()) {
(*i)->Close();
break;
}
}
if (i != mConnections.end()) {
mConnections.erase(i);
}
SDL_mutexV(mpConnectionsMutex);
}
//-----------------------------------------------------------------------------
void Server::Band(uint32_t ip)
{
SDL_mutexP(mpBandConnectionsMutex);
list<uint32_t>::const_iterator i;
for (i = mBandConnections.begin(); i != mBandConnections.end(); ++i) {
if (ip == *i) {
break;
}
}
if (i == mBandConnections.end()) {
mBandConnections.push_back(ip);
}
SDL_mutexV(mpBandConnectionsMutex);
Kick(ip);
}
//-----------------------------------------------------------------------------
void Server::Unband(uint32_t ip)
{
SDL_mutexP(mpBandConnectionsMutex);
list<uint32_t>::iterator i;
for (i = mBandConnections.begin(); i != mBandConnections.end(); ++i) {
if (ip == *i) {
break;
}
}
if (i != mBandConnections.end()) {
mBandConnections.erase(i);
}
SDL_mutexV(mpBandConnectionsMutex);
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// $Log$
///////////////////////////////////////////////////////////////////////////////
// vim:ts=2:sw=2:sts=2:et
I do not believe I implemented any of this in a standard way, I just took a guess at how it could be done, I know for shore that my Kick() code is rather bad, as it relies on a read error from the clients Recieve() by closing while it is being read to kick them off.
What I plan on doing for the client is connect to the ip 255.255.255.255 with the port number of say 4567, and hope it will connect to my server, which is where the client and server will shake hands exchanging information. So that the clients can get their server lists, and the servers can get the clients to put in the Loby. I have a feeling thow that this will not work now, since I used the ip address 255.255.255.255 already to create my server,
as can be seen in the following code. The INADDR_ANY stores 0xFFFFFFFF (255.255.255.255). The code for reading and writing data is in the Socket class it inherits from.
Code:
///////////////////////////////////////////////////////////////////////////////
// $Id$
// $Revision$
///////////////////////////////////////////////////////////////////////////////
#include <string>
#include "ServerSocket.h"
using namespace std;
//-----------------------------------------------------------------------------
ServerSocket::ServerSocket(uint16_t port): mPort(0)
{
IPaddress ip;
ip.host = INADDR_ANY;
ip.port = mPort;
mSocket = SDLNet_TCP_Open(&ip);
if (mSocket == 0) {
throw string("ServerSocket::ServerSocket: ") += SDLNet_GetError();
}
}
//-----------------------------------------------------------------------------
ServerSocket::~ServerSocket()
{
}
//-----------------------------------------------------------------------------
void ServerSocket::Accept(Socket* pSocket)
{
pSocket->mSocket = SDLNet_TCP_Accept(mSocket);
if (mSocket == 0) {
throw string("ServerSocket::Accept: ") += SDLNet_GetError();
}
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// $Log$
///////////////////////////////////////////////////////////////////////////////
// vim:ts=2:sw=2:sts=2:et
Does anyone have a better way of doing what I tring to do???
:newbie: