#include <simpleserver.h>
Inheritance diagram for ssobjects::SimpleServer::
Public Types | |
enum | { MIN_FREQ = 10 } |
Public Methods | |
SimpleServer (const SockAddr &saBind, const unsigned32 nFreq=1000, const unsigned32 nMaxConnections=100) | |
Single-threaded constructor. More... | |
SimpleServer (ServerSocket *const psocket, const unsigned32 nFreq) | |
Multi-threaded constructor. More... | |
virtual | ~SimpleServer () |
virtual void | startServer () |
Starts up the server, makes ready for connections. More... | |
virtual void | killServer () |
Stops server, and closes all connections. More... | |
virtual void | pauseIncomingConnections () |
(Not currently in use.) Server will no longer accept connections. More... | |
virtual void | sendPacket (ServerSocket *psocket, const PacketBuffer &packet) |
Sends a packet over a socket. More... | |
virtual void | sendPacket (ServerSocket *psocket, const PacketBuffer *ppacket) |
Sends a packet over a socket. More... | |
virtual void | send2All (const PacketBuffer &packet) |
Sends a packet to all client sockets connected to the server. More... | |
virtual void | send2All (const PacketBuffer *ppacket) |
Sends a packet to all client sockets connected to the server. More... | |
virtual void | removeSocket (ServerSocket *psocket) |
Removes a socket from the server. More... | |
unsigned32 | getTicks () |
System timer ticks. More... | |
bool | isThreaded () |
Check if server is in single or multi-threaded mode. More... | |
Static Public Methods | |
bool | canBind (SockAddr &saBind) |
Checks if we are able to bind. good for when you are about to start the server. More... | |
Protected Methods | |
virtual void | processSingleMsg (PacketMessage *pmsg)=0 |
Override this to process packets that come in from clients. More... | |
virtual void | idle (unsigned32 nTimer=0) |
Override to have a timer in your server. More... | |
threadReturn | ThreadHandlerProc (void) |
void | processMessages () |
bool | processSockets (int iReady) |
void | processSelectError () |
void | acceptConnection () |
int | getMaxFD () |
long | getSleepTime () |
void | addMsg (PacketMessage *pmsg) |
void | queClosedMessage (ServerSocket *psocketRemoving) |
Protected Attributes | |
SocketInstance | m_sListen |
SockAddr | m_saServer |
LinkedList< ServerSocket > | m_listClients |
PacketMessageQue | m_que |
unsigned32 | m_nIdleFrequency |
unsigned32 | m_nMaxCon |
bool | m_bUsingThread |
bool | m_bPause |
unsigned32 | m_nSleepTime |
timeval | m_tvServerStarted |
fd_set | m_rset |
fd_set | m_wset |
Overview
Simple server is a class that you dirive from to create a fully functional server. The simple server class handles creating a listen socket, reading full packets from a client connection, and idling the server.
You only need to override processSingleMsg() in order to process packets that come from a client socket. idle() is overridden if you want to have an idle task.
The two ways of constructing a simple server are for a single-threaded server, and a multi-threaded server.
User overridables
namespace ssobjects processSingleMsg()
idle()
Components
o Message Pump
o Idler
Message Pump
The message pump is the way the server talks to your code. When data comes into the server, it is first parsed into packets, and a PacketMessage is created that references the packet and the socket that it was sent from. It is then posted to the message que. Once there, processSingleMsg is called for every packet that was parsed from the incoming data.
This is where your code comes into play. You check what the packet command was, then extract the data from the packet if appropreate, perform some kind of operation, and perhaps send a reply back. This is the process of processing a clients request.
Care should be taken to make sure that when processSingleMsg is called, your operations don't take very long. In a single threaded environment, all other packets - and there-for all the clients - will waiting for you to process thier requests.
Idler
Idling is the process of repeating tasks at a regular interval, like having a main loop, or more accuratly, like using a WM_TIMER message in Windows. The frequency is controlled by the m_nFrequency attribute.
Override idle() method if you want to do things on a regular basis without waiting for a packet from a client. This is prefered over putting the server into a busy loop. If the server is in a busy loop, it will not process additional packets in a single-threaded environment. You can set how often this is called via the frequency attribute.
Threading
It is possible to write the server in such a way that it will operate as a single-threaded server or a multi-threaded server, and this decision can be made at run time. It simply requires a little for-planning, and knowing where to put shared data.
The reason you would want to have a server capable of running as a single or threaded server is for debugging purposes under Linux. Single threading is easier to debug. Multi-threaded can give better performance, and is the best way to handle lengthy operations.
Threading requires the use of the SimpleManager object. It's a little tricky to setup.
|
|
|
Single-threaded constructor. This constructs the server object to run as a single threaded server. [Win32] WSAStartup is called at this point. You should construct the server before calling canBind method.
|
|
Multi-threaded constructor. Creating a simple server as a handler for a socket. This constructor is used in the simple manager. The socket is already attached. This instance of a simple server is meant to be run multi-threaded.
|
|
Destroys the server object, closes the listening socket, removes all msg's in the message que, removes all client socket connects and closes them. [Win32] Calls WSACleanup() |
|
Reimplemented from ssobjects::ThreadHandler. |
|
|
|
|
|
Checks if we are able to bind. good for when you are about to start the server. Creates a listen socket and tries binding it using the port information passed in. Once the connection has been bound, the connection is put into listen mode, and is then closed. Good for when you want to start the server in single threaded mode, but need to make sure that you were able to bind. When using the protocol address in saBind, this will bind this server to a specific IP address. Useful when the machine this server is running on has more then one IP address assigned to it. See the manpage on bind for more details.
|
|
|
|
|
|
System timer ticks.
|
|
Override to have a timer in your server.
|
|
Check if server is in single or multi-threaded mode.
|
|
Stops server, and closes all connections.
|
|
(Not currently in use.) Server will no longer accept connections.
|
|
|
|
|
|
Override this to process packets that come in from clients.
The server will call this method when there was enough data to have parsed it into a packet and needs to have the packet processed. A PacketMessage object is created to contain both the packet and client socket that send the packet. You will typically send your reply to this socket. In certain circumstances you will send the reply to all client connections such as in the case of a chat message. When you override this method, your function will typically look something like:
... void YourServer::processSingleMsg(PacketMessage* pmsg) { ServerSocket* psocket = (ServerSocket*)pmsg->socket(); PacketBuffer* ppacket = pmsg->packet(); switch(ppacket->getCmd()) { //One way to handle the message. Process and reply within the switch. case PacketBuffer::pcPing: //do something importaint sendPacket(psocket,PacketBuffer(PacketBuffer::pcPong)); //send a reply pong break; //The prefered way to handle the message. Keeps the switch clean. case PacketBuffer::pcGetVersion: onGetVersion(pmsg); break; } DELETE_NULL(ppacket); //IMPORTANT! The packet is no longer needed. You must delete it. } ... void YourServer::onGetVersion(PacketMessage* pmsg) { ServerSocket* psocket = (ServerSocket*)pmsg->socket(); PacketBuffer version(PacketBuffer::pcVersion); //create the reply packet version << "Version: 1.0"; //insert the version information into the packet sendPacket(psocket,version); //send the packet to the client socket } ... For more information see the Message Pump section in the Detailed Description section.
|
|
|
|
Creates and posts a PacketBuffer::pcClosed message to the server message que. The message contains the socket handle, and the ip address in dotted decimal format. The socket you pass in is the socket that you are removing. The socket should still be valid (not yet deleted) when this method is called.
|
|
Removes a socket from the server. Removes this socket from our client list, deletes the object, and posts a message to say that this guy is gone. Once this function returns, the socket passed in can no longer be used. Undefined behavior will occur If you attempt to use the socket after a call to this function. You will receive a pcClosed message in a call to processSingleMsg. Included in the message is the socket number, and dotted decimal IP address that was attached to the socket. You should no longer use the socket number, or the socket object. Typically, you store the socket number in a list somewhere so when a socket is closed, you will be able to find it and remove it from your user data.
|
|
Sends a packet to all client sockets connected to the server. Use this when you want to send a packet to all client connections.
|
|
Sends a packet to all client sockets connected to the server. Use this when you want to send a packet to all client connections.
|
|
Sends a packet over a socket.
|
|
Sends a packet over a socket.
|
|
Starts up the server, makes ready for connections. Creates the listen socket, binds to the address passed in at construction, and puts the listen socket into listen mode. This method does not return until the server has stopped. The message pump and idler are your only access points after this call. You would typically do any setup you need to do before this is called. Once this returns, the server object can be destroyed. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|