ServerMain.cpp
file that puts together the objects required to run the server and configures them, and SocketServer.h
and SocketServer.cpp
files that provide a link between the framework and the socket server callbacks that you will implement to act on various network events that happen during the lifetime of the connections to your server. We'll start by looking at the SocketServer.h
file. For the simplest UDP EchoServer this file could look something like this:
#include "JetByteTools\SocketTools\DatagramSocketServer.h" #include "ServerCommon\DatagramSocketServerCallback.h" class CSocketServer : public JetByteTools::Socket::CDatagramSocketServer, private CDatagramSocketServerCallback { public : CSocketServer( const JetByteTools::Socket::IFullAddress &address, const JetByteTools::Socket::ListenBacklog listenBacklog, JetByteTools::IO::IIOPool &pool, JetByteTools::Socket::IAllocateDatagramServerSockets &socketAllocator, JetByteTools::IO::IAllocateBuffers &bufferAllocator, const JetByteTools::Socket::SocketBufferSize recvBufferSize, const JetByteTools::Socket::SocketBufferSize sendBufferSize, JetByteTools::Socket::ILimitConnections &connectionLimiter = JetByteTools::Socket::CConnectionLimiter::NoLimitLimiter); ~CSocketServer(); private : // Implement just the bits of IDatagramSocketServerCallback that we need virtual void OnReadCompleted( JetByteTools::Socket::IDatagramServerSocket &socket, JetByteTools::IO::IBuffer &buffer); // Our business logic void EchoMessage( JetByteTools::Socket::IDatagramServerSocket &socket, JetByteTools::IO::IBuffer &buffer) const; /// No copies do not implement CSocketServer(const CSocketServer &rhs); /// No copies do not implement CSocketServer &operator=(const CSocketServer &rhs); };
CSocketServer
class derives from the framework's basic UDP server class but it doesn't actually need to except for the convenience of being able to manipulate a single object as your server. The important base class is the CDatagramSocketServerCallback
as this allows you to override just the callback functions that you're interested in dealing with rather than having to provide a default implementation for the whole of IDatagramSocketServerCallback
. void CSocketServer::OnReadCompleted( IDatagramServerSocket &socket, IBuffer &buffer) { try { Output(_T("ReadCompleted - socket: ") + ToString(&socket) + _T(" - ") + CAddressRenderer::AsString(socket.GetRemoteAddress(), true)); EchoMessage(socket, buffer); } catch(const CException &e) { Output(_T("ReadCompleted - Exception - ") + e.GetDetails()); } catch(...) { Output(_T("ReadCompleted - Unexpected exception")); } }
OnReadCompleted()
handler is called and we are given a buffer which contains the bytes that made up the datagram. EchoMessage()
function and, well, this is what it does with them: void CSocketServer::EchoMessage( IDatagramServerSocket &socket, IBuffer &buffer) const { DEBUG_ONLY(Output(_T(" Local Address: ") + CAddressRenderer::AsString(socket.GetLocalAddress(), true))); DEBUG_ONLY(Output(_T("Remote Address: ") + CAddressRenderer::AsString(socket.GetRemoteAddress(), true))); DEBUG_ONLY(Output(_T("Data Echoed -\r\n") + DumpData(buffer.GetMemory(), buffer.GetUsed(), 60, true))); socket.Write(buffer); }
ServerMain.cpp
is pretty much identical except for the type of socket allocator used.