Creating Servers for handling Multiple clients
                              Fog Edition
			       By FireNet

(This document is dedicated to my friend Aaron Anderson)

(Fog Edition means I dont tell you everything stright.All the info will be there but you will have to do much thinking)

Servers and Clients,the backbone of the internet after the TCP/IP protocol.Right now I will go
yak yak on TCP/IP so if you know it skip this.Also I intend not to provide you with everything.
I will provide enought material and directions for you but you will have to do something on your
own.I just teach you how to setup a basic server which can accept multiple connection and
of course guidlines on how to make a robust server.We will also look into a very simple kind of
server 'Chat servers'.

TCP/IP
-------
TCP stands for Transmission Control Protocol.IP stands for Internet Protocol Address.TCP
implementations provides a defined way about how data transmissions can be done over
the wire between diffrent computers.There are a few sub protocols but we wont worry about
them since they are at a lower level.

OSI Model
----------
It is an open standard published by the ISO(International Standards Organisation) on how
systems can recive and transmit data with each other.TCP/IP is an implemetation of it.
It has 7 layers and each do a diffrent job.We dont want to go into details now.

This helps various computer with diffrent hardware and OS to communicate with each other
without any special work and diffrent OS can transfer data transperantly.This enable a
network to consit of diffrent machines and still transfer data without a problem

http://www.webopedia.com/quick_ref/OSI_Layers.asp

How TCP works
---------------
A basic overview of course.When a client wants to connect to a server it send an SYN
packet to the server.The server responds with a SYN/ACK packet to which the client responds
with a ACK packet.

Client  ---> SYN  --->  Server
Client  <--- SYN/ACK  <--- Server
Client ----> ACK  --->  Server

This is called a 3 way TCP/IP hand shake.Then the connection is ready for transmitting data.
The data sent is broken up into multiple packets and sent between the client and server.There
are mechanisims to ensure that the packets are recived and assembled in the correct order
and the data has not been corrupted.If it has been corrupted the data has to be retransmitted.
Along with a lot more protections, error checks etc etc ....

We never see any of this as they are handled at lower levels so we dont need to worry about them.

Ports
-----
The ships dock here.Actually ports are a way to seperate diffrent connections.When a
client connects to a server there mabe more than one service running on that machine or if the data
is sent to the client how,does one say which app gets that data.Ports range from 0-6255.They serve
to identification which service a client wants to access or which client app should get the info.

Now you got a very basic intro on how computers communicate we can go about designing servers.
I will provide a basic client here with will be used for testing.We will not disscuss it much.

/*-------------------Echo_client.cpp-------------------*/
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <iostream.h>
#include <conio.h>
#include <signal.h>
#include <stdio.h>

//DECLARATIONS
	//error trapping signals
	  #define SIGINT 2
	  #define SIGKILL 9
	  #define SIGQUIT 3
	//SOCKETS
	  SOCKET sock,client;

void s_handle(int s)
{
	if(sock)
	   closesocket(sock);
	if(client)
	   closesocket(client);
	WSACleanup();
	cout<<"EXIT SIGNAL :"<<s;
	exit(0);
}


void s_cl(char *a, int x)
{
	cout<<a;
	s_handle(x+1000);
}

void main()
{
	//Declarations
	int res,i=1,port=100;
	char buf[100];
	WSADATA data;
	
	signal(SIGINT,s_handle);
	signal(SIGKILL,s_handle);
	signal(SIGQUIT,s_handle);
	
	cout<<"\t\tEcho Client";
	
	
	sockaddr_in ser;
	sockaddr addr;
	
	ser.sin_family=AF_INET;
	ser.sin_port=htons(port);					//Set the port
	ser.sin_addr.s_addr=inet_addr("127.0.0.1");		//Set the address we want to connect to
	
	memcpy(&addr,&ser,sizeof(SOCKADDR_IN));
	
	res = WSAStartup(MAKEWORD(1,1),&data);		//Start Winsock
	cout<<"\n\nWSAStartup"
		<<"\nVersion: "<<data.wVersion
		<<"\nDescription: "<<data.szDescription
		<<"\nStatus: "<<data.szSystemStatus<<endl;

	if(res != 0)
		s_cl("WSAStarup failed",WSAGetLastError());

	sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);		//Create the socket
		if(sock==INVALID_SOCKET )
			s_cl("Invalid Socket ",WSAGetLastError());
		else if(sock==SOCKET_ERROR)
			s_cl("Socket Error)",WSAGetLastError());
		else
			cout<<"Socket Established"<<endl;
	
	res=connect(sock,&addr,sizeof(addr));				//Connect to the server
		if(res !=0 )
		{
			s_cl("SERVER UNAVAILABLE",res);
		}
		else
		{
			cout<<"\nConnected to Server: ";
			memcpy(&ser,&addr,sizeof(SOCKADDR));
		}
	
	while(true)
	{
		cout<<"\n>";
		gets(buf);
		
		res =  send(sock,buf,100,0);		//Send Data
	
		if(res==0)
		{	
			//0==other side terminated conn
			printf("\nSERVER terminated connection\n");
			closesocket(client);
			client =0;
			break;
		}
		else if(res==SOCKET_ERROR)
		{	
			//-1 == send error
			printf("Socket error\n");
			s_handle(res);
			break;
		}
		
		
	res=recv(sock,buf,100,0);		//Recive Data
	
	if(res>0)
	{
		cout<<"\nRecieved string:"<<buf;
	}
	
  }	
	WSACleanup();
}
/*-------------------Echo_client.cpp-------------------*/

Server Mania
-------------
There is a curse which goes "May you live in interesting times" and making servers will only help it.
Planning is as improtant here as it is else where.I will give a few basics by which you should be able
to plan and build your own servers with multiple client support.

We will build a single thread server with support for multiple clients.All info about a client will be kept
in a structure and funtions will use that info to perform various jobs.

Client Sturcture:

struct _client
{
	bool con;			//Set true if a client is connected
	sockaddr_in addr;	//Client info like ip address
	SOCKET cs;		//Client socket
	fd_set set;			//used to check if there is data in the socket
	int i;				//any piece of additional info
};

The obvious funtions we need are:

accept(_client *);		//accept client connections
recv(_client *);			//recive data from them
send(_client *);			//send data

Globals:

MAX_CONS		//Total No of Client allowed
PR_CONS		//No of currently connected clients

We will build a version of an echo server.Any data sent by any client is sent to all the clients connected.
Chat server work in a similar manner.We will be doing a bare bones server and wont put in too much
error checking.


Basic Server Skeleton
---------------------
This describes how a server is structured.

1.Initialise a few variables i.e. the port,ip etc of the server
2.Start Winsock.(A must for windows server and clients)
3.Create the Socket
4.Set the Socket options
5.Bind the server to a port
6.Set Listen Mode
7.Set non-blocking mode.(Important if your server supports multiple clients or is gui)
8.Start the server loop
9.Exit server loop and cleaup memory
10.Stop Winsock.

Note:Of course most parts have their own error checks.

Now the server is not very much diffrent from the client see below for steps 1 to 7.

/****************SERVER.cpp****************/
void main()
{
	int res,i=1,port=100;
	WSADATA data;
	
	cout<<"\t\tEcho Server (Multiple Client Support)";
	
	sockaddr_in ser;
	sockaddr addr;
	ser.sin_family		=	AF_INET;
	ser.sin_port		=	htons(port);
	ser.sin_addr.s_addr 	= 	INADDR_ANY;
	
	memcpy(&addr,&ser,sizeof(SOCKADDR_IN));	
	
	res = WSAStartup(MAKEWORD(1,1),&data);
	cout<<"\n\nWSAStartup"
		<<"\n Version: "<<data.wVersion
		<<"\n Description: "<<data.szDescription
		<<"\n Status: "<<data.szSystemStatus<<endl;
	
	if(res != 0)
		s_cl("WSAStarup failed",WSAGetLastError());
	
	sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
		if(sock==INVALID_SOCKET )
			s_cl("Invalid Socket ",WSAGetLastError());
		else if(sock==SOCKET_ERROR)
			s_cl("Socket Error)",WSAGetLastError());
		else
			cout<<"SOCKET Established"<<endl;
	
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&i,sizeof (i));
	
	res = bind(sock,&addr,sizeof(addr));
	cout<<"Binding socket:"<<res<<endl;
		if(res != 0)
			s_cl("BIND FAILED",WSAGetLastError());
		else
			cout<<"Socket Bound to port : "<<port<<endl;
	
	
	res = listen(sock,5);
	cout<<"Server Listen mode : "<<res<<" Size = "<<m*2<<endl;
	
	unsigned long b=1;
	ioctlsocket(sock,FIONBIO,&b);
/****************SERVER.cpp****************/

Notes
------

1.htons()
This funtions is used make port numbers correct according the hardware.This is
due to the fact the diffrent hardware store numbers diffrently.If this is not called
clients from other computers will not be able to establish a connection.

2.bind() - binds the server to a specified port

3.listen()
This is used to set the listen mode and set the max amount of packets that will be allowed
to be stored at a time.If the no of packets exceed the limit they will be conveniently dropped.

4.ioctlsocket();
Set the blocking mode.Set b to one to make the socket a non-blocking one.In non blocking
mode the funtions will return immediately even if they have not got any respone.This will prevent
them from stopping the program operation till they get a response.This will enable us to loop through
all the clients and respond to the ones who have sent commands.Eg.In blocking mode the accept()
will wait till it recives a connection before it returns and in non-blocking mode it returns immediately.


Server Loop
------------
This is where all the work of a server is done

while(true)
{
	accept_clients();		//Recive connections
	send_clients();		//Send data to clients
	recv_clients();		//Recive data from clients
}

That's it basically.Of course the the 3 funtions will be very similar to a simple server but they will
also have to handle some more work.


Low Level funtions
------------------
In a simple server we used funtions accept(),send(),recv() to interact with the client.
We will now overload them to do our work.


Accept funtion
---------------

int accept(_client *x)
{
	x->i = sizeof(sockaddr);
	x->cs = accept(sock,(sockaddr *)&x->addr, &x->i);

	if(cs != 0 && cs !=SOCKET_ERROR)
	{
		x->con = true;
		FD_ZERO(&x->set);
		FD_SET(x->cs,&x->set);
		return (true);
	}
	return (false);
}

Notes
------
x->cs = accept(sock,(sockaddr *)&x->addr, &x->i)
is quite note worthy.Here we assign the return of the funtion to another SOCKET(x->cs) variable.
We will be using this variable to communicate with the client.'sock' will be used only for
accepting connections.

(x->addr) will have all client related info like the IP address.

The rest is simple.If the return is valid then set the connection status (i.e x->con) to true and
initialise the fd_set.This will be used to check if data is present in the socket.

Send Funtion
-------------

int send(_client *x,char *buffer,int sz)
{
	x->i = send(x->cs,buffer,sz,0);
	if(x->i == SOCKET_ERROR || x->i == 0)
	{
		disconnect(x);
		return (false);
	}
	else return (true);
}

Notes
x->i is used just because it's avilable,use another one if you like.
If there is a socket error or the return is 0 disconnect.I recomment you
find some out.We will be making disconnect() later.Zero means the client
has disconnecter.-1 i.e socket error means the client is unreachable due
to any reason.

Recv Function
--------------

int recv(_client *x,char *buffer,int sz)
{
	if(FD_ISSET(x->cs,&x->set))
	{
		x->i = recv(x->cs,buffer,sz,0);
		if(x->i == 0)
		{
			disconnect(x);
			return (false);
		}
		return (true)
	}
	
	return (false);
}

That's it you have all the basic structre and low level stuff you need to build a simple server.
Now we are free to tackle building a robust server.

Building Robust Servers
----------------------
Bang,Crash,Hi,Hello,Crack,Oh master,ha,Woof............... sounds weird.Well they repesent
how diffrent client connect and how they behave.Some leave by saying good bye others
leave the line open,other disappear etc etc.

So one of the most important things for any server would be to keep track of client connections.
Connections appear and disappear at random so it best to have some central command to keep
track of server status and various connection details.The major problem will be clients disappearing
if we are not implementing a lot of checks( like now). We will be relying on the send funtion mainly to
see if a client has left us or is unreachble.That means recv() will not show any error unless a client
has quit properly but send will pick up a missing client.This is not much of a problem since you will
almost always have to send data to client continously.If no activity( i.e sending) then a improperly
disconnected client will remain in the memory and will not noticed untill you send it some data.This
should not pose any probs anyways so no need to worry about this.

Its best to have a server as modular as possible to enable modifiactions (which will be extensive)
without breaking any code.That would make things like porting(ie getting it to work on other OSs)
upgrading etc easy.

Oh yes there are always memory, it's alway limited, even if you are in a sea of memory,llike the old
saying goes "water,water everywhere not drop to drink".Other problems include things like buffer
overflows and illegal memory access.Brr goes crazy very quickly if your server has even 1 leak.

Now these are the few common problems.There are more when you go to make your server more
funtional.Following a few guidelines will sure help reduce them.(Noodles but you cant have it anyother
way)

1.If random memory access is used always provide for errors and deallocate memory on crashing
2.As far as possible never hard code anything.
3.Use defines when values have to be hard coded
4.Modularity is a must.Keep funtional code seperate from network code
5.Memory should always be conserved.
6.If linked lists are used, use a manager class to use them through,never directly
7.Seperate your code into diffrent segments and keep them in diffrent headers
8.Always develop funtions to check the status and look for errors on your server including
but not limited to no. of clients, memory usage, client details etc.
9.Try for max performance even if you are on a supercomputer.

This should be enough for a start.I will only discuss a few of them.The others you have to
figure out.

Modularity
----------
Oh,well you should know it so I will just brush on it.Why you still need it?Security
Yes,that wonderful oxcymoron.If all your send and recive are channeled through
one place it will be eaiser to implemet restrictions and permmisions.So reduce the number
of places you call recv(sock... or send(sock... to one place and use higher level funtions
to call them.Try to limit the network code as much as possible.Also seperate the recive,
send, and accept funtions.This will enable you to go multi-thread without trearing anything.

Status and Error Monitering
---------------------------
Develop these early.They will be a great help for debuging your code.

Well below you will see what a status monitor looks like.You can build diffrent ones if you like
or even integrate it with the lower level funtions.It's better if all this goes to a central location
as you will always be informed.

Of course not just one funtion can do all the work.You will have to develop ones which will have to
look at each connection as report details like the IP address etc.Also debug funtions.

[Maybe more,but in a biginner tut it wont be of much use]


Back to coding ---- >

The server loop is given below.You will have to develop the funtions on your own.Hey do say
this is a tut and all has to be told.I did tell everything.I gave you funtions to handle send, recive
and accept through the client structure dint I.All you have to do now is make a glorified loop.

while(true)
{
	accept_clients();		//Recive connections
	send_clients();		//Send data to clients
	recv_clients();		//Recive data from clients
}

I wont leave you hanging up on a tree though

_client client[MAX_CONS];

void accept_clients()
{
	for(int i=0;i<MAX_CONS;i++)
	{
		if(!client[i].con)		//i.e a client has not connected to this slot
		{
			if(accept(client[i]))
			{
				//update server status
				Server_Status(CLIENT_CON);
			}
		}
	}
}

Server_Status(int msg)
{
	if(msg == CLIENT_CON)
	{
		PR_CONS++;
		cout<<"\nWow, a client has connected";
	}
	else if(msg == CLIENT_DIS)
	{
		PR_CONS--;
		cout<<"Wee, a client has disconnected";
	}
	else
	{
		//never leave out anything
		cout<<"\n>>>>>>We got an unknown message :"<<msg;
	}
}

void disconnect(_client *x) //this is called by the low level funtions
{
	if(x->cs)closesocket(x->cs);
	x->con = false;
	x->i = -1;
	Server_Status(CLIENT_DIS);
}

That's it,now you have enough stuff to setup a server that will accept multiple connections.


Chat Servers
-------------
Chat servers are the easy to build since they have little work to do and require no protocol.
The code I gave above is sufficent to build a simple one.You will just have to build recv_clients()
and a chat_message(char *s).

Now let look at what a basic chat server does.Well a client connect,nick names himself,and
the types messages which are transmitted to everyone.I wont show how to handle the nick
registration (you do that) but I will show you a way to respond to a command and a simple
chat message.

Let's say all our commads start with a / and they will be handled server side.Ok get hold of the
server code I already gave and put in the server loop.You will have to define the messages,MAX_CONS
and PR_CONS.(also remove the send_client() will will not need that here).

Thse chat_message funtion just has to send a text message to all connected clients.

void chat_message(char *s)
{
	int len = strlen(s);
	
	for(int i=0;i<MAX_CONS;i++)
	{
		if(client[i].con)		//valid slot,i.e a client has parked here
		{
			send(client[i],s,len);
		}
	}
}

Now the recive funtion has to get a message from any client who sends a message

#define BF_SZ 100

void recv_client()
{
	char buffer[BF_SZ]
	
	for(int i=0;i<MAX_CONS;i++)
	{
		if(client[i].con)		//valid slot,i.e a client has parked here
		{
			if(recv(client[i],buffer,BF_SZ))
			{
				if(buffer[0]=='/')
				{	
					//respond to commands
					if(strcmp(buffer,"/server_bang")==0)
					{
						chat_message("8*8* The Server Goes BANG *8*8");
					}
				}
				else
				{
					chat_message(buffer);
				}
			}
		}
	}
}

Naturally,Now you have a chat server,but you cant say who said what.For that you will have to
add a char variable to the _client struct respond to a command to assign the nick.Then add the nick
to the beginig of every message and voila a better chat server.More polish would invlove alerting
all the clients when a fellow connects or disconnects.(Server_Stats() can do that).No need for
me to do that it's simple and you will get more satisfaction if you do it.Else it will be no more than
copy paste.You now have enough potential to build your own server for any purpose.(For God's
sake dont make IRC yet,just add more commands and polish and some status display funtions)

--------------------------------
				     Protocols
				(Basic overview)
			--------------------------------

Very boring.Diplomats use it a lot.Nah computer potocols are much more interesting.It's
a specified way in which a client and a server talk.

Eg of a protocol

struct chat_protocol
{
	int id;
	char nick[10];
	char msg[100];
};

What !!! that's just a structure.Well my friend deplomats never say even a simple thing simply
you know.Some times life is very simple.Now how do you use this.Simple,any file i/o.

send(sock,(char*)&prt_buff,sizeof(chat_protocol),0);
	recv(sock,(char*)&prt_buff,sizeof(chat_protocol),0);

It's as simple as that.This was a very simplistic view.I dont really care to go into the jargon
when dealing with newbies.

Actually a protocol define how large a transmission is,what it is made up of,and where to find what.

Eg.The first byte to the 2nd byte will contain an integer containing an id.The next 10 byte will contain
the nick name.The rest will contain the message.That how a protocol would be on paper so that others
can implement it in their programms which may not be in C/C++ and then they will still be able to
communicate with your server.C++ make this stuff quite easy as you can see :-).

Of course there can be sub-protocols as well.The string terminator NULL ('\0') is another protocol
you could say.It tells us where the string ends.Aowsome eh ?

--------------------------------
				     Security
				   (Concerns)
			--------------------------------

Well you know diplomats they never say anything directly and a lot of things said are not
what they seem at the surface and maybe more shallow or deeper that you think.Never
trust them blindly.

Let me drive it home.Look at the chat_protocol above.Take the msg char variable.Now
if you use cout<< it should display some text.But suppose a client has filled the entire
100 bytes with charA without a \0.What happens then.Your server will happily start reading
the string, cross the limit and go into restricted parts till it hits a \0 or CRASHES !!.A simple
buffer overflow exploit.

Always be careful with read/write limits.This should be enough to get you worried so when
you make your servers keep such things in mind.Always.

[From personal experiance.When I used to work on a simple chat server I noticed that I could
over write a part of memory to get past restrictions by simply setting a huge nickname.It over
wrote an int which stored my current permission.The permission check funtion used to give normal
permission as default.ie

if(check)
{
	perm = 9;
}
else if (check == 222)
{
	perm = 8;
}
else perm = normal;

As far as possible dont do that and handle only conditions which can be predicted.Everything
else should generate an error message and any possible action like disconnecting the client]

That's a wrap folks.You know have a little above the beginners level of knowledge of building
servers and it various factors and concerns.

[You should be able to find the full source of the chat server on my site,compare it with yours]

Name:	Aaron M.(a.k.a FireNet)
E-Mail:	[email]xfirenet@hotmail.com[/email]
Website:	[url]www.xlock.ssr.be[/url]
                 [url]http://xlock.hostcubix.com/[/url]

- Burn Out /*">"£"£)£")£"$"£("£&^£"

[Exit notes:Well you should have got a nice overview of building servers quickly and in a cut-trought fasion.I will post some compleated code and and few notes concerning a few things which I have not really dealt with,and links to more resources of course]

Here is the server made by Aaron Anderson (to him is this tutorial dedicated) exactly how it was sent to me.Compare it with your code.

I would like to add the Anderson has an excellent coding style and great
potential as a coder.He is dedicated to his work and very through.I wish
him very best.This server is done very well and is no copy paste job.

/*

// COMMENTS //

	Author	:	xmen90s -> based on the tutorial of Aaron aka FireNet
				[email]xmen90s@yahoo.com[/email]

	Date	:	June 10th of 2004

	Purpose	:	This server receives input from multiple clients and keeps
				a RAM database of a few pieces of information like screen
				name, character model, and position
				The server then will echo back information to all clients
				instructing them on where to move actors

				Essentially I'm working on rebuilding the multiplayer system
				of a game called Dungeon Siege from ground up.

	I want to put a special thanks out to Aaron aka FireNet for writing
	the most excellent tutorial I have ever read.  I went from knowing
	cin and cout to writing a full non-blocking multi-client echo server
	in just one and a half weeks because of him.

// LINKS //

	Remember to link to : wsock32.lib

*/

// INCLUDE FILES //

#include <fstream.h>
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>

// DEFINITIONS //

#define		PORT 4000		// Define the port to connect to
#define		MAX_CLIENTS 10	// Define the maximum number of clients we can receive
#define		BUFFER_SIZE 256 // Define the buffer size of the messages

// STRUCTURES //

struct _client
{
	bool		connected;
	sockaddr_in	address;
	SOCKET		socket;
	fd_set		socket_data;
	int			address_length;

	char		template_name[15];
	char		screen_name[15];
	char		siegepos[45];
};

// GLOBAL VARIABLES //

sockaddr_in	server_address;
sockaddr	server_socket_address;
SOCKET		server_socket;

_client		client[MAX_CLIENTS];
int			clients_connected = 0;

// FUNCTION DECLARATIONS //

bool	accept_client ( _client *current_client );
int		accept_connections ();
int		disconnect_client ( _client *current_client );
void	echo_message ( char *message );
void	end_server();
void	midcopy ( char* input, char* output, int start_pos, int stop_pos );
int		receive_client ( _client *current_client, char *buffer, int size );
void	receive_data();
int		send_data ( _client *current_client, char *buffer, int size );
void	start_server();

// FUNCTION DEFINITIONS //

bool accept_client ( _client *current_client )
{
	// Accept incoming connections
	current_client->address_length = sizeof ( sockaddr );
	current_client->socket = accept ( server_socket, ( sockaddr * ) &current_client->address, &current_client->address_length );

	if ( current_client->socket == 0 )
	{
		// No data in socket
		return ( FALSE );
	}
	else if ( current_client->socket == SOCKET_ERROR )
	{
		// Socket error
		return ( FALSE );
	}
	else
	{
		// Occupy the client slot
		current_client->connected = TRUE;
		FD_ZERO ( &current_client->socket_data );
		FD_SET ( current_client->socket, &current_client->socket_data );

		return ( TRUE );
	}

	return ( FALSE );
}

int accept_connections()
{
	if ( clients_connected < MAX_CLIENTS )
	{
		for ( int j = 0; j < MAX_CLIENTS; j++ )
		{
			if ( !client[j].connected )
			{
				if ( accept_client ( &client[j] ) )
				{
					// Increment the client count
					clients_connected++;

					// Grab the ip address of the client ... just for fun
					char *client_ip_address = inet_ntoa ( client[j].address.sin_addr );

					// Output connection
					cout << "ACCEPTING CLIENT to array position [" << j << "] with IP ADDRESS " << client_ip_address << endl;
				}
			}
		}
	}

	return ( 1 );
}

int disconnect_client ( _client *current_client )
{ // Disconnect a client
	if ( current_client->connected == TRUE )
	{ // Close the socket for the client
		closesocket ( current_client->socket );
	}

	// Set the new client state
	current_client->connected = FALSE;

	// Clear the address length
	current_client->address_length = -1;

	// Decrement the current number of connected clients
	clients_connected--;

	// Declare a variable to store the disconnect message into
	char raw_data[BUFFER_SIZE];

	// Parse in the client data to send
	sprintf ( raw_data, "~4 %s", current_client->screen_name );

	// Echo out the disconnect message so all clients drop this client
	echo_message ( raw_data );

	cout << "Disconnecting client[]" << endl;

	return ( 1 );
}

void echo_message ( char *message )
{
	for ( int j = 0; j < MAX_CLIENTS; j++ )
	{
		if ( client[j].connected )
		{ // Echo the message to all clients
			send_data ( &client[j], message, BUFFER_SIZE );
		}
	}
}

void end_server()
{ // Shut down the server by disconnecting all clients and clearing winsock
	// Disconnect all clients
	for ( int j = 0; j < MAX_CLIENTS, j++;) { disconnect_client ( &client[j] ); }

	// Close the listening socket for the server
	closesocket ( server_socket );

	// Clean up winsock
	WSACleanup();
}

void midcopy ( char* input, char* output, int start_pos, int stop_pos )
{
	int index = 0;

	for ( int i = start_pos; i < stop_pos; i++ )
	{
		output[index] = input[i];
		index++;
	}

	output[index] = 0;
}

int receive_client ( _client *current_client, char *buffer, int size )
{
	if ( FD_ISSET ( current_client->socket, &current_client->socket_data ) )
	{
		// Store the return data of what we have sent
		current_client->address_length = recv ( current_client->socket, buffer, size, 0 );

		if ( current_client->address_length == 0 )
		{ // Data error on client
			disconnect_client ( current_client );

			return ( FALSE );
		}

		return ( TRUE );
	}

	return ( FALSE );
}

void receive_data()
{
	char buffer[BUFFER_SIZE];

	for ( int j = 0; j < MAX_CLIENTS; j++ )
	{
		if ( client[j].connected )
		{
			if ( receive_client ( &client[j], buffer, BUFFER_SIZE ) )
			{
				if ( buffer[0] == '~' )
				{ // All data should be buffered by a '~' just because

					if ( buffer[1] == '1' ) // Add Client Command
					{
						// Declare the buffer to store new client information into
						char raw_data[BUFFER_SIZE];

						// Parse out the 'Add Client' command
						midcopy ( buffer, raw_data, 3, strlen ( buffer ) );

						// Store the client information into our RAM client database
						sscanf ( raw_data, "%s %s %s", client[j].template_name, client[j].screen_name, client[j].siegepos );

						for ( int k = 0; k < MAX_CLIENTS; k++ )
						{
							if ( ( client[k].connected ) && ( j != k ) )
							{
								// Parse in the client data to send
								sprintf ( raw_data, "~1 %s %s %s", client[k].template_name, client[k].screen_name, client[k].siegepos );

								// Send the client data
								send_data ( &client[j], raw_data, BUFFER_SIZE );
							}
						}
					}
					else if ( buffer[1] == '2' ) // Move Client Command
					{
						// Declare the buffer to store new client information into
						char raw_data[BUFFER_SIZE];

						// Parse out the 'Move Client' command
						midcopy ( buffer, raw_data, 3, strlen ( buffer ) );

						// Update the client information into our RAM client database
						sscanf ( raw_data, "%s %s", client[j].screen_name, client[j].siegepos );
					}
					else if ( buffer[1] == '3' ) // Chat Client Command
					{
						// ECHO THE MESSAGE BACK TO ALL CLIENTS
					}
					else if ( buffer[1] == '4' ) // Remove Client Command
					{
						// Disconnect the current client
						disconnect_client ( &client[j] );
					}

					// Display all data received
					// cout << buffer << endl;

					// Echo the message to the other clients
					echo_message ( buffer );

					// Clear the buffer
					buffer[0] = '/0';
				}
			}
		}
	}
}

int send_data ( _client *current_client, char *buffer, int size )
{
	// Store the return information about the sending
	current_client->address_length = send ( current_client->socket, buffer, size, 0 );

	if ( ( current_client->address_length == SOCKET_ERROR ) || ( current_client->address_length == 0 ) )
	{ // Check for errors while sending
		disconnect_client ( current_client );

		return ( FALSE );
	}
	else return ( TRUE );
}

void start_server()
{ // Initialize the server and start listening for clients
	// LOCAL VARIABLES //
	WSADATA wsaData;
	int res, i = 1;

	// Set up the address structure
	server_address.sin_family = AF_INET;
	server_address.sin_addr.s_addr = INADDR_ANY;
	server_address.sin_port = htons ( PORT);

	// IM GUESSING : Copy over some addresses, conversions of some sort ?
	memcpy ( &server_socket_address, &server_address, sizeof ( SOCKADDR_IN ) );

	res = WSAStartup ( MAKEWORD ( 1, 1 ), &wsaData );

	// Start winsock
	if ( res != 0 ) 
	{
		cout << "WSADATA ERROR : Error while attempting to initialize winsock." << endl;
	}

	// Create a listening socket for the server
	server_socket = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP );

	if ( server_socket == INVALID_SOCKET )
	{
		cout << "SOCKET ERROR : Invalid socket." << endl;
	}
	else if ( server_socket == SOCKET_ERROR )
	{
		cout << "SOCKET ERROR : Socket error." << endl;
	}
	else
	{
		cout << "SOCKET ESTABLISHED" << endl;
	}

	// Sets the option to re-use the address the entire run of the program
	setsockopt ( server_socket, SOL_SOCKET, SO_REUSEADDR, ( char * ) &i, sizeof ( i ) );

	// Bind the socket to the address
	res = bind ( server_socket, &server_socket_address, sizeof ( server_socket_address ) );

	cout << "Binding socket:" << res << endl;

	if ( res != 0 )
	{
		cout << "BINDING ERROR : Failed to bind socket to address." << endl;
	}
	else
	{
		cout << "Socket Bound to port : "<< PORT << endl;
	}

	// Start listening for connection requests
	res = listen ( server_socket, 8 );

	// This makes the server non blocking, hence it won't wait for a response
	unsigned long b = 1;
	ioctlsocket ( server_socket, FIONBIO, &b );

	// Clear all clients state
	for ( int j = 0; j < MAX_CLIENTS; j++ ) { client[j].connected = FALSE; }
}

////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////

// MAIN FUNCTION //

int main()
{
	cout << "\txmen90s Non-Blocking Multi-Client Echo Server for Dungeon Siege\n" << endl;

	// Initialize winsock and start listening
	start_server();

	// Loop forever
	bool looping = TRUE;

	while ( looping )
	{
		// Accept all incoming client connections
		accept_connections();

		// Receive all data from clients
		receive_data();
	}

	// Shut down winsock
	end_server();

	return 0;
}

You #include <stdio.h> twice. Anyway, besides that little error, this is just the thing I have been looking for. Thanks, mate!

Hello,

I tried to use that code, written by FireNet and mr Anderson. Actually I am studiying socket networking for a while now. I allredy wrote a working default (blocking) server and client.

The problem is, that I cannot connect to that (non-blocking) server with echo client, also written in previous post by mr. Anderson.

The client always prints "SERVERUNAVALILIBLEEXIT SIGNAL: 999" which probbably means, that client connect function call returns -1.

If I watch server behavior, and it doesnt write anything. So it looks like, the server doesn't get any connecting client from network. I'd be really glad when somebody could help me by that problem.

I work in Vista, and tried allredy in localhost mode (server and client on same computer), than I tried also to have server on other computer in LAN (and I changed server IP address in client) and still nothing works. I read about function accept, but really don't know how to use it and as written in previous posts, the code should work such, as it is written allredy.

Many thanks for help,

Domen Zupančič

This article has been dead for over six months. Start a new discussion instead.