BWY Systems Server Overview

Powering Your TCP/IP Socket Server

BWY Systems Server is a library for Windows and Linux that is easily integrated to give your socket server application high performance and stable I/O completion ports capability.

What is I/O Completion Ports (IOCP)?

IOCP (I/O completion ports) is the most high performance socket model available in the programming world. On Microsoft's Windows OS they have provided a set of Win32 API functions for creating various asynchronous socket models such as the event model and overlapped model, but their best conception to date has proven to be the IOCP model. IOCP is designed to be used with a thread pool, where the programmer would create multiple worker threads to service the completed socket events. The way this works is by associating each socket with a handle called a completion port. The worker threads then use this completion port handle to wait for any posted socket events. When one of the socket events completes or finishes, one of the worker threads is then awaken and can be used to process the event (such as sent or received data). After the processing is finished the thread should then wait on the completion port for another event.

This concept is extremely powerful, as never before has a TCP/IP socket server application ever been able to handle so many TCP/IP connections while utilizing such little system resources. If you look back to the basic Berkley socket model, the programmer would normally create a new thread for every connection, which on a high usage application would exhaust the system resources. IOCP is a great leap to more powerful and robust applications.

Under the BWY Systems Server Hood

The BWY Systems Server library exports very simple to use, yet powerful, set of functions that simply mask the complexities of the IOCP code. All of the events are relayed through call back functions that you create and provide when setting up your "Server handle" (the unique handle associated with the listening TCP server you create).

Example

The following is a very simple example of how to get a basic I/O completion ports TCP server up and running using the BWY Systems Server library.

#include <stdlib.h>
#include <stdio.h>
#include <BWYSystemsServer.h> // All that's needed for the library.

#ifdef WIN32
#pragma comment(lib, "BWYSystemsServer.lib") // Link to the library to get
					     // the exported functions.
#endif

// Declare the server call back functions:
VOID WINAPI ServerInitThreadProc(HANDLE hServer, LPVOID &lpThreadData);
VOID WINAPI ServerExitThreadProc(HANDLE hServer, LPVOID lpThreadData);
BOOL WINAPI ServerRecvProc(HANDLE hServer, LPVOID &lpThreadData, HANDLE hClient,
				BYTE *lpRecv, ULONG nRecvSize, BOOL &bFreeBuffer);
BOOL WINAPI ServerConnectProc(HANDLE hServer, LPVOID &lpThreadData, HANDLE hClient);
VOID WINAPI ServerDisconnectProc(HANDLE hServer, LPVOID &lpThreadData, HANDLE hClient);


int main(int argc, char **argv)
{
	HANDLE hServer = NULL;
	BWYSERVERSETUP Setup;

	// Initialize the Setup structure:
	Setup.nListenPort = 5050;
	Setup.nSockets = BWYSERVER_DEFAULT; // Use the default number of accept sockets
					    // to be created and ready for new connections.
	Setup.nThreads = BWYSERVER_DEFAULT; // Use the default number of worker threads
					    // (initially based on the number of processors).
	Setup.lpListenAddress = NULL;
	Setup.ServerConnectProc = ServerConnectProc;
	Setup.ServerDisconnectProc = ServerDisconnectProc;
	Setup.ServerExitThreadProc = ServerExitThreadProc;
	Setup.ServerInitThreadProc = ServerInitThreadProc;
	Setup.ServerRecvProc = ServerRecvProc;
	Setup.lpGlobalData = (LPVOID)NULL;
	// Create the Server:
	hServer = BWYServerCreate(&Setup);

	// At this point all worker threads are created and the listening socket is
        // binded to port 5050 (specified above).

	...

	// Do something here like user input, ect...

	...


	// Close down the Server:
	if(hServer != NULL)
	{
		BWYServerClose(hServer);
		hServer = NULL;
	}

	return 0;
}


VOID WINAPI ServerInitThreadProc(HANDLE hServer, LPVOID &lpThreadData)
{
	// This function will be called for every worker thread
	// that is created.

	// You could do something here to initialize anything
	// associated with this new worker thread.
}

VOID WINAPI ServerExitThreadProc(HANDLE hServer, LPVOID lpThreadData)
{
	// This function is called for every thread upon shutdown.
}

BOOL WINAPI ServerConnectProc(HANDLE hServer, LPVOID &lpThreadData, HANDLE hClient)
{
	// This function is called for every newly connected socket.

	return TRUE; // Return TRUE to allow the connection or FALSE to reject it.
}

VOID WINAPI ServerDisconnectProc(HANDLE hServer, LPVOID &lpThreadData, HANDLE hClient)
{
	// This function is called every time a socket is disconnected.
}

BOOL WINAPI ServerRecvProc(HANDLE hServer, LPVOID &lpThreadData, HANDLE hClient,
				BYTE *lpRecv, ULONG nRecvSize, BOOL &bFreeBuffer)
{
	// This function is called every time data is received on a socket.

	bFreeBuffer = TRUE; // Notify the Server that it is not needed
			    // to buffer the received data.
	printf("Data received!\r\n");

	return TRUE; // Return TRUE to continue the connection with the
		     // client or FALSE to disconnect the client.
}