| | |
Winsock Multi-Client Servers
![]() |
C++ Syntax (Toggle Plain Text)
Creating Servers for handling Multiple clients Fog Edition By FireNet
(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.
C++ Syntax (Toggle Plain Text)
Client ---> SYN ---> Server Client <--- SYN/ACK <--- Server Client ----> ACK ---> Server
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.
C++ Syntax (Toggle Plain Text)
/*-------------------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:
C++ Syntax (Toggle Plain Text)
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 };
C++ Syntax (Toggle Plain Text)
accept(_client *); //accept client connections recv(_client *); //recive data from them send(_client *); //send data
C++ Syntax (Toggle Plain Text)
MAX_CONS //Total No of Client allowed PR_CONS //No of currently connected clients
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.
C++ Syntax (Toggle Plain Text)
/****************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****************/
------
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
C++ Syntax (Toggle Plain Text)
while(true) { accept_clients(); //Recive connections send_clients(); //Send data to clients recv_clients(); //Recive data from clients }
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
---------------
C++ Syntax (Toggle Plain Text)
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); }
------
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
-------------
C++ Syntax (Toggle Plain Text)
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); }
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
--------------
C++ Syntax (Toggle Plain Text)
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); }
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.
C++ Syntax (Toggle Plain Text)
while(true) { accept_clients(); //Recive connections send_clients(); //Send data to clients recv_clients(); //Recive data from clients }
C++ Syntax (Toggle Plain Text)
_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); }
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.
C++ Syntax (Toggle Plain Text)
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); } } }
C++ Syntax (Toggle Plain Text)
#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); } } } } }
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)
C++ Syntax (Toggle Plain Text)
-------------------------------- Protocols (Basic overview) --------------------------------
a specified way in which a client and a server talk.
C++ Syntax (Toggle Plain Text)
Eg of a protocol struct chat_protocol { int id; char nick[10]; char msg[100]; };
you know.Some times life is very simple.Now how do you use this.Simple,any file i/o.
C++ Syntax (Toggle Plain Text)
send(sock,(char*)&prt_buff,sizeof(chat_protocol),0); recv(sock,(char*)&prt_buff,sizeof(chat_protocol),0);
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 ?
C++ Syntax (Toggle Plain Text)
-------------------------------- Security (Concerns) --------------------------------
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
C++ Syntax (Toggle Plain Text)
if(check) { perm = 9; } else if (check == 222) { perm = 8; } else perm = normal;
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]
C++ Syntax (Toggle Plain Text)
Name: Aaron M.(a.k.a FireNet) E-Mail: <a href="mailto:xfirenet@hotmail.com">xfirenet@hotmail.com</a> Website: <a rel="nofollow" class="t" href="http://www.xlock.ssr.be" target="_blank">www.xlock.ssr.be</a> <a rel="nofollow" class="t" href="http://xlock.hostcubix.com/" target="_blank">http://xlock.hostcubix.com/</a>
[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.
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.
C++ Syntax (Toggle Plain Text)
/* // COMMENTS // Author : xmen90s -> based on the tutorial of Aaron aka FireNet <a href="mailto:xmen90s@yahoo.com">xmen90s@yahoo.com</a> 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 * ) ¤t_client->address, ¤t_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 ( ¤t_client->socket_data ); FD_SET ( current_client->socket, ¤t_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, ¤t_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; }
•
•
Join Date: Jul 2009
Posts: 3
Reputation:
Solved Threads: 0
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č
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č
![]() |
Similar Threads
- Accessing Database through Client (Winsock) ??? (Visual Basic 4 / 5 / 6)
- Pretty Advanced Winsock communication: HTTP servers (C++)
- Multi Thread Help (Java)
- multi-client server [problem with code - please have a look] (Java)
- GALAXY - Sun Launches Newest Servers (IT Professionals' Lounge)
Other Threads in the C++ Forum
- Previous Thread: Heap only accepts on object.
- Next Thread: Listening for keyboard input without pausing the program?
| Thread Tools | Search this Thread |
api array based binary bitmap business c++ c/c++ char class classes code codesamplerunwhilecommands coding commentinghelp compile console conversion count decide delete deploy desktop developer directshow dll download dynamic dynamiccharacterarray email encryption error faq file forms free fstream function functions game givemetehcodez graph guess gui hash homeworkhelp homeworkhelper iamthwee ifpug ifstream incrementoperators input int integer java lib linkedlist linker listing loop looping loops map math matrix memory multiple news node output pointer port problem proficiency program programming project python random read recursion reference rpg string strings temperature template test text text-file tree url variable vector video win32 windows winsock wordfrequency wxwidgets





