General Archives

Another release is coming...


We've only just shipped Release 6.6.5 of The Server Framework but we already have another release that's just about to ship. This isn't because some horrible bug has slipped through our testing, it's because we've been planning to produce a 'clean up' release for some time. 6.7 is that release.

Lets be straight here, 6.7 is a release for us more than for you. The aim is to simplify our build/test and release process, remove dead code whilst introducing no new bugs and removing no functionality that you rely on.

So what does 6.7 achieve. Well, for a start we drop support for Visual Studio 2005 and 2008 and also for Windows XP. Removing support for these legacy compilers and operating systems means that we can remove all the code that was required just to support them. This massively simplifies our code base without removing anything that the code actually relies on to run on modern operating systems.

Windows Vista introduced massively important changes to asynchronous I/O and we have supported these changes for a long time (over 8 years!). The code required to jump through hoops to make code running on Windows XP behave was complex. For example, Windows XP would cancel outstanding I/O requests if the thread that issued them exited before the I/O request completed. We had a marshalling system in place to ensure that I/O operations were only ever executed on threads that we controlled so that you'd never be faced with unexpectedly cancelled operations. All of that can go now.

Removing XP also means we no longer need to maintain an XP machine in our build farm. It's one less configuration that needs to be built and tested before a release.

Dropping support for VS2005 and 2008 removes 4 complete sets of builds (x86 and x64 for each compiler) plus all of the conditional code that was required to support the older compilers. At last we can start moving towards a slightly more modern C++, perhaps.

Some old code has been removed; there's no need, on modern operating systems, to share locks. This worked really well back in the day, but, well, we were running on Windows NT at the time and resources were much more limited than they are now. All of the "Shared Critical Section" code is now gone. This has knock on effects into the Socket Tools library where all of the shared lock socket code has been removed. Nobody should be using that in 2016 anyway! You can no longer set a critical section's spin count in the socket allocator, it never really worked anyway as the lock was used for too many different things.

Some experimental code has also been removed; The TLS and Low Contention buffer allocators are gone. The horrible "dispatch to all threads" cludge has been removed from the I/O pools (it was only there to support pre-Vista CancelIO() calls which are no longer needed now that we have CancelIOEx()).

The original callback timer queue that was based on GetTickCount() and which spawned Len's "Practical testing" series of blog posts (back in 2004!) has gone. There's no need for the complexity when all supported operating systems have GetTickCount64().

Finally we've slimmed down our set of example servers. Removing servers which didn't add much value or which duplicated other examples. Again, this speeds our release process by speeding up the build and test stage as there are fewer servers to build and fewer tests to run.

So, what's in it for you? Well, a faster build/test/release cycle so new functionality and bug fixes can be released quicker and potentially faster code in some circumstances. There's no great rush to upgrade if you don't want to, but we'll be focusing on the 6.7 code base going forwards.

A while back a client of mine had an issue with a TLS 1.2 connection failing during the TLS handshake. We couldn't see any issues with the code and if we only enabled TLS 1.1 on the server then the connection handshake worked just fine.

Eventually we tracked the issue down to the fact that the certificate in use had been signed with MD5 and that MD5 isn't a valid hash algorithm for TLS 1.2 and so the handshake failed when SChannel attempted to validate the certificate and found that it was unacceptable. There's a Microsoft blog posting about this problem here.

Annoyingly the error message for this is: "The client and server cannot communicate, because they do not possess a common algorithm." which is bang on the money, but doesn't help much until after you've worked out what the problem is. We were already dumping out the enabled algorithms and protocols and couldn't understand why the connection either wasn't working or wasn't downgrading to TLS 1.1.

I've now added some certificate investigation code to the point where my example SChannel servers set up their contexts. This at least allows me to warn and degrade to TLS 1.1 if the certificate is not going to work with TLS 1.2. In production systems I expect we'd just fail to start up.

   CCredentials::Data data;

   data.cCreds = 1;
   data.paCred = &pCertContext;

   // Note that for TLS 1.2 you need a certificate that is signed with SHA1 and NOT MD5.
   // If you have an MD5 certificate then TLS 1.2 will not connect and will NOT downgrade
   // to TLS 1.1 or something else...

   DWORD dataSize = 0;

   if (::CertGetCertificateContextProperty(
      ByteBuffer buffer(dataSize);

      BYTE *pData = buffer.GetBuffer();

      if (::CertGetCertificateContextProperty(
         const _tstring signHashDetails(reinterpret_cast<tchar *>(pData), dataSize);

         if (signHashDetails.find(_T("MD5")) != _tstring::npos)
            if (enabledProtocols == 0 || enabledProtocols & SP_PROT_TLS1_2)
               OutputEx(_T("Certificate is signed with: ") + signHashDetails);
               OutputEx(_T("MD5 hashes do not work with TLS 1.2 and connection downgrade does NOT occur"));
               OutputEx(_T("This results in failure to connect. Disabling TLS 1.2"));

               if (enabledProtocols)
                  enabledProtocols &= ~SP_PROT_TLS1_2;

               if (!enabledProtocols)
                  // if enabledProtocols is zero then all protocols are
                  // enabled, so we need to explicitly enable everything
                  // except TLS1.2

                  enabledProtocols = SP_PROT_SSL3TLS1;

   data.grbitEnabledProtocols = enabledProtocols;

WSARecv, WSASend and thread safety

Last week I learnt something new, which is always good. Unfortunately it was that for over 15 years I'd been working under a misconception about how an API worked.

Tl;dr When using WSARecv() and WSASend() from multiple threads on a single socket you must ensure that only one thread calls into the API at a given time. Failure to do so can cause buffer corruption.

It all began with this question on StackOverflow and I dived in and gave my usual response. Unfortunately my usual response was wrong and after spending some time talking to the person who had asked the question and running their test code I realised that I've been mistaken about this for a long time.

My view has always been that if you issue multiple WSARecv() calls on a single socket then you need to be aware that the completions may be handled out of sequence by the threads that you have servicing your I/O completion port. This is purely due to thread scheduling and the actual calls to WSARecv() are thread safe in themselves. I wrote about this here back in 2002. My belief was that you could safely call WSARecv() from multiple threads on the same socket at the same time and the only problem would be resequencing the reads once you processed them. Unfortunately this is incorrect as the example code attached to the question shows.

The example code is somewhat contrived for a TCP socket in that it doesn't care about the sequencing of the read completions and it doesn't care about processing the TCP stream out of sequence. It issues multiple WSARecv() calls from multiple threads and the data being sent is simply a series of bytes where the next byte is the value of the current byte plus one and where we wrap back to zero after a 'max value' is reached.

Such a stream with a max value of 7 would look like this: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03...

Validating such a TCP stream is as simple as taking any read that completes in any order and simply ensuring that the bytes that are contained in the buffer that has been returned follow the expected pattern. Starting from the first byte, whatever value it is, subsequent bytes must be one greater until the 'max value' is reached at which point the wrap to zero and continue to increment. Assuming my long held beliefs were true then it didn't matter how many threads were issuing WSARecv() calls on the socket at the same time, the resulting slices of the TCP stream should all be valid.

Unfortunately the test program fails to prove this and instead proves that without synchronisation around the WSARecv() call the returned stream slices can be corrupt. That is the data in the buffers returned from the read completion can include bytes that do not follow the expected pattern.

Of course the way that the test program uses the API is of limited use as I can't think of a TCP stream where it would be useful to be able to process the stream in randomly sized chunks with no need to have processed the data that comes before the current data. One of the reasons that I believed that I understood the requirements of the API was that I never used it this way. In systems where multiple reads on TCP streams were allowed I would always increment a sequence number, put the sequence number in the read buffer's meta data and then issue the WSARecv() all as an atomic step with locking around it. This made it possible to correctly sequence the read completions and also had the side effect of preventing multiple threads calling WSARecv() on a single socket at the same time. However, with UDP sockets the broken usage pattern is much more likely and I think that I may have seen the corruption on a client's system in the past - we're testing with fixed code now.

I've yet to fully investigate the WSASend() side of the problem but I'm assuming that the issue is the same. The person who asked the question on StackOverflow has seen data corruption when the receive side is protected by synchronisation and the send side isn't and I've no reason to doubt his analysis. I would like to think that calling WSASend() on one thread and WSARecv(), on another on the same socket, at the same time, is OK, but for now I'm assuming it's not and simply using a single lock per socket around both calls.

The current documentation for WSARecv() has this to say about thread safety: If you are using I/O completion ports, be aware that the order of calls made to WSARecv is also the order in which the buffers are populated. WSARecv should not be called on the same socket simultaneously from different threads, because it can result in an unpredictable buffer order. Which, IMHO, doesn't actually address this issue. It mentions the unpredictable buffer order, which is expected, but not the buffer corruption. Also the documentation for WSASend() has an identical note with "WSARecv" replaced by "WSASend", which, when you think about it, doesn't actually make sense at all. I don't remember seeing these notes when I was first looking at the documentation, but who knows (yes, I'd like a fully preserved set of all revisions to the MSDN docs so that I can diff back to what the docs said when I wrote the code ;) ). Network Programming for Microsoft Windows, Second Edition, doesn't mention any thread safety issues at all in its coverage of WSASend() and WSARecv() as far as I can see from a brief scan.

Apart from the one known case of UDP datagram corruption that may be caused by my misunderstanding I think most of our systems are pretty safe just by their design. However, there will be a fix included in the 6.6.3 release and 7.0 wont be susceptible to this problem at all due to its Activatable Object usage at the socket level.

It's always good to learn something new, more so when it challenges long held beliefs and especially when it proves those beliefs to have been incorrect.

New client profile: Eonic Gaming - Turf Battles

We have a new client profile available here for a new client who is using The Server Framework to power their MMORPG game server.

UDP flow control and asynchronous writes


I don't believe that UDP should require any flow control in the sending application. After all, it's unreliable and it should be quite OK for any stage of the route from one peer to another to decide to drop a datagram for any reason. However, it seems that, on Window's at least, no datagrams will be dropped between the application and the network interface card (NIC) driver, no matter how heavily you load the system.

Unfortunately most NIC drivers also prefer not to drop datagrams, even if they're overloaded (see here for details of how UDP checksum offloading can cause a NIC to make non-paged pool usage considerably higher). This can lead to situations where a user mode application can bring a box down due to non-paged pool exhaustion simply by sending as many datagrams as it can as fast as it can. It's likely that it's actually poorly implemented device drivers that are at fault here; by failing to gracefully handle situations where non-paged pool allocations fail, but it's the application that is putting these drivers into a situation where they could fail in such a catastrophic manner.

Since the NIC driver and the operating system will not drop datagrams it's down to the application itself to do so if it senses that it's overloading the NIC. I've recently added code to The Server Framework to allow you to configure behaviour like this so that an application can prevent itself from exhausting non-paged pool due to pending datagram writes.

New client profile: Wave Systems Corp.

We have a new client profile available here for a new client who is using The Server Framework for secret things that they can't tell us about!

New client profile: Chinese Company - M2M Server

We have a new client profile available here for a new client who selected The Server Framework to replace its previous networking layer in an M2M server which deals with 20,000 devices connected via GPRS.

New client profile: Tricerat Inc. - Printer sharing

We have a new client profile available here for a client who uses The Server Framework in their Printer presence and print job transfer system.

They use both the OpenSSL Option Pack and the SSPI Option Pack in their product. The ease of adding security and authentication which can communicate with a disparate selection of clients is one of the strong points of developing with The Server Framework.
We have a new client profile available here for a new French client who uses The Server Framework in an M2M server to control its smart alarm panels.
We have a new client profile available here for a new Chinese client who uses The Server Framework to build servers for its GIS applications for the Oil and Gas industry.
We have a new client profile available here for a new client who selected The Server Framework to build the servers for its iOS and Android games.
Be aware that there is a known bug in Windows 8 and all Server 2012 variants which causes AcceptEx() completions to be delayed in some situations. This was confirmed by a Microsoft representative on Microsoft Connect, see the error report ticket here. An example of how to demonstrate this bug, its likely affects and the current know causes can be found here in this Stack Overflow question.

I'm a little disappointed with the official response to this bug report. I wasn't expecting a fix to be included in the imminent release of Server 2012 but it would be nice to get more information back from Microsoft about what the actual cause of the problem is. Right now the Stack Overflow question is the only source of information about what may cause this problem and which API calls it is caused by and affects. Given that it appears to be a bug in how IOCP completions are dispatched for threads that issued I/O requests but are now in some kind of blocking state (possibly something to do with APC dispatch and the fact the blocking thread is not currently in an alertable wait state - but this is all guess work).

Note that it is unlikely that code built with The Server Framework will suffer any problems from this bug. We always suggest that you never do blocking calls on I/O threads and all of our AcceptEx() calls (except the first ones which are usually issued when the server starts up) are made from an I/O thread. As long as you are following our advice and are using a separate thread pool for potentially blocking operations then your code should run just fine even on operating systems where this bug is present.

I will be issuing a bug fix release shortly which will marshal the initial AcceptEx() calls that are made when you call StartAcceptingConnections() off of the calling thread and onto one of the I/O pool threads. This is an easy change which will require no changes to non library code and will remove any chance that these initial AcceptEx() calls could suffer from delayed completion if you happen to call an inappropriate Windows API on that thread (currently just a synchronous ReadFile() or anything that itself calls down to a synchronous ReadFile()).

Note that this bug only affects AcceptEx() completions and so only affects servers that use the CStreamSocketServerEx class.
There's an interesting question over on stack overflow about a perceived change in IOCP behaviour on Windows 8 (and Server 2012 RC).

The question includes some code which demonstrates how an overlapped AcceptEx() call is blocked on by the thread that issued it being blocked inside a call to ReadFile() at the time that the AcceptEx() completes. The completion for the AcceptEx() is delayed until the ReadFile() completes even though a thread is waiting for completions on the IOCP associated with the socket. The "delaying" behaviour only shows up on Windows 8 and Windows Server 2012 RC. On all other platforms everything works "as expected" and the fact that the thread that issued the AcceptEx() has blocked in no way affects the completion of the accept.

I can't see anything wrong with the example code (and I've also tested with code which loads AcceptEx() "correctly" using WSAIoctl(), but I may be missing something... I can reproduce the issue here and I can confirm that the problem does not affect WSARecv() calls (that is, I changed the example to use WSAAccept() to accept the connection in a blocking manner and then issue an overlapped WSARecv() before entering the blocking ReadFile() and everything works as expected.

This is a slightly worrying change for those of us using AcceptEx() from arbitrary threads! I've yet to check to see if the stalled accept completion blocks the head of the IOCP and stalls ALL subsequent completions on the IOCP or if it is simply blocking the accept completion...

With The Server Framework you could switch to disabling JETBYTE_STREAM_SOCKETS_SKIP_MARSHAL_TO_IO_POOL and force all I/O to be done by one of the I/O threads. Assuming you perform no blocking calls on your I/O threads then you would be fine.

I expect I'll add a further option which will let you forcibly marshal just AcceptEx requests to the I/O pool when running on Windows 8/Server 2012... Unfortunately existing code which uses AcceptEx and is compiled with JETBYTE_STREAM_SOCKETS_SKIP_MARSHAL_TO_IO_POOL enabled could fall foul of this rather strange change in the underlying operating system.

Hopefully this is a bug which will get fixed pretty quickly!
We have a new client profile available here for a new client who selected The Server Framework to help it expand its online gaming platform to incorporate a WebSockets interface.
We are dropping support for Visual Studio .Net 2002 from release 6.6 of The Server Framework which is due early next year. We don't expect that this will cause anyone any problems as this compiler became unsupported by Microsoft in 2009, and most native C++ people seemed to skip this release entirely.

We are also considering dropping support for Visual Studio .Net 2003. This compiler is still supported by Microsoft until 2013 but we expect that most people interested in native C++ will have switched to Visual Studio 2005 or 2008 at the earliest opportunity.

Feedback is essential here. If you DO still need Visual Studio .Net 2003 support then we need to know, otherwise we may bring forward its retirement date...
We have a new client profile available here for a client that we've had since 2006 and who use The Server Framework in their equity trading systems.
Some stream protocols have the concept of 'out of band' (OOB) data. This is a separate logical communication channel between the peers which enables data that is unrelated to the current data in the stream to be sent alongside the normal data stream. This is often a way for some data to jump ahead of the normal stream and arrive faster than if it were delivered via the the normal data stream.

Winsock supports out of band data in a protocol independent way, see here, but accessing it from networking code that uses overlapped I/O rather than the old-fashioned BSD API is somewhat under documented. By default, out of band data does not appear in the normal data stream, you have to read it explicitly by setting MSG_OOB in the flags of a call to WSARecv(). For non overlapped I/O designs you can use WSAAsyncSelect() or select() to explicitly check for the presence of out of band data. With overlapped I/O your options appear limited, it seems that you should be able to use an overlapped WSAIoctl() call with SIOCATMARK but this will return immediately when OOB is either present or not present, it doesn't wait for OOB to become available.

The solution is to post a separate, out of band, overlapped WSARecv() passing the MSG_OOB flag. This will only return on socket closure or when out of band data arrives. By using a distinct indicator in your 'per operation data' you can distinguish this read from normal reads and deal with it accordingly. Once you have processed the special out of band data read you can then post another to read subsequent out of band data.

A little note to all you Chinese hackers

My server logs are showing that there are some people currently trying to hack this site. They appear to be mainly Chinese. I assume you think you might be able to download the source code to The Server Framework for free if you manage to hack my websites; after all the same IP addresses have been exploring my sites a lot and looking at lots of the documentation pages on here...

Anyway, you're wrong. The source doesn't live on these internet facing servers and never has done, all that's there are the publicly accessible examples.

Please go away.

And of course, to anyone who isn't trying to hack the site, happy browsing!

New client profile: MiX Telematics

We have a new client profile available here for a client that we've had since 2009 and who use The Server Framework in their vehicle tracking software.
To enable network applications to send and receive data via a TCP connection reliably and efficiently the TCP protocol includes flow control which allows the TCP stack on one side of the connection to tell the TCP stack on other side of the connection to slow down its data transmission, or to stop sending data entirely. The reason that this is required is that the TCP stack in each peer contains buffers for data transmission and data reception and flow control is required to prevent a sender from sending when a receiver's buffer is full. The flow control is accomplished by adjusting the window size of the sliding window acknowledgment system that is used by TCP.

New client profile: inConcert

We have a new client profile available here for a client that began by using The Free Framework and then switched to using The Server Framework to take advantage of the advanced features that it offers.

New client profile: Cadcorp

We have a new client profile available here for a client that began using The Server Framework in its GeognoSIS web mapping product in September 2010.
When building TCP client server systems it's easy to make simple mistakes which can severely limit scalability. One of these mistakes is failing to take into account the TIME_WAIT state. In this blog post I'll explain why TIME_WAIT exists, the problems that it can cause, how you can work around it, and when you shouldn't.

New client profile: RTE Network

We have a new client profile available here for a client that we've had since 2006 in the IP Fax business.

New client profile: Desktop Sharing Company

We have a new client profile available here for a client that we've had since 2006 in the desktop sharing market. Their system, built on The Server Framework, runs on more than 120 servers worldwide and handles more than 200,000 desktop sharing sessions each day!
I found this article recently whilst discussing a question about socket reuse using DisconnectEx() over on StackOverflow. It's a useful collection of the various configuration settings that can affect the number of concurrent TCP connections that a server can support, complete with links to the KB articles that discuss the settings in more detail. It's a bit out of date, but it's probably a good starting point if you want to understand the limits involved.

Note that I've never had to tune or tweak the default settings (apart from setting MaxUserPort to allow more outbound connections).
Using a modern Windows operating system it's pretty easy to build a server system that can support many thousands of connections if you design the system to use the correct Windows APIs. The key to server scalability is to always keep in mind the Four Horsemen of Poor Performance as described by Jeff Darcy in his document on High Performance Server Architecture. These are:

  • Data copies
  • Context switches
  • Memory allocation
  • Lock contention
I'll look at context switches first, as IMHO this is where outdated designs often rear their head first. On Windows systems you MUST be using I/O Completion Ports and overlapped I/O if you want the best scalability. Using the IOCP API correctly can mean that you can service thousands of concurrent connections with a handful of threads.

So, we'll assume we're using a modern overlapped I/O, IO Completion Port based design; something similar to what The Server Framework provides, perhaps. Using an IOCP allows you to limit the number of threads that are eligible to run at the same time and the IOCP uses a last in, first out mechanism to ensure that the thread that was last active and processing is always the next one to be given new work, thus preventing a new thread's memory needing to be paged in. 

The latest versions of Windows allow you to reduce context switching even further by enabling various options on each socket. I've spoken in detail about how FILE_SKIP_COMPLETION_PORT_ON_SUCCESS can help to reduce context switching on my blog, here. The gist is that with this option enabled you can process overlapped operation completions on the same thread that issued the operation if the operation can complete at the time it's issued. This removes unnecessary context switching. The Server Framework supports this mode of operation on operating systems that support it.

Next on to data copies, as Jeff says in his document, one of the best ways to avoid data copies is to use reference counted buffers and to manage them in terms of the amount of data present in them, building buffer chains where necessary. The Server Framework has always worked in terms of flexible, reference counted buffers. Many server designs can benefit from accumulating inbound data into a single buffer with no buffer copying required simply by reissuing a read on a connection with the buffer that was passed to you when the previous read completed. In this way it's easy to accumulate 'complete messages' and process them without needing to copy data. 

Since the buffers are reference counted you can easily pass them off to other threads for processing, or keep them hanging around until you're done with them. The CMultiBufferHandle class allows you to use scatter/gather I/O so that you can transmit common blocks of data without needing to copy the common data and the CBufferHandle class allows you to broadcast data buffers to multiple connections without needing to copy the data for each connection.

Memory allocation during connection processing is minimal and custom buffer allocators can reduce this even further. The Server Framework ships with several different allocators and it's easy to implement your own if you need to and simply plug it in to the framework code. By default the buffer and socket allocators pool memory for reuse which helps reduce contention and improve performance.

Once you're processing your messages several tricks can be employed to optimise your memory allocation use, a favourite of mine is to use custom memory allocators that use scratch space in the buffer that the message was initially read into. This can then be used to provide all of the dynamic memory needed during message processing and avoids the need for traditional memory management and its potential lock contention.  

Lock contention within the framework itself is limited. The design of the socket object is such that you can design a server where there's never any need to access a common collection of connection objects simply to obtain per connection data from it. Each connection can have as much user data as you like associated with it and this can all be accessed from the connection without the need for any locks. The locks in the buffer allocators are probably the most likely locks to result in contention but here you can select from several different strategies, including a lock free allocator. 

Of course once you've our of the framework code and into your own code you still have to be careful not to fall foul of the Four Horsemen of Poor Performance, but you can rest assured that The Server Framework is designed very much with these issues in mind. I believe that the only way to make sure that you maintain scalability and performance is to test for it at all stages of development, it's important to set up scalability tests from day 1 and to run them regularly using real world usage scenarios. I'll talk about how to go about setting up these kinds of tests in a later blog post.

Welcome to

| 0 Comments is a new website that we've put together to make it easier for users and potential users of the licensed version of our high performance, I/O completion port based client/server socket framework to find all of the information that they need. As many of you know, I've been working on the code that forms The Server Framework since 2001 and it's been used by lots of our clients to produce highly scalable, high performance, reliable servers that often run continuously 24/7, all year round. Up until now the code hasn't really had a consistent name; but that's changed. Although the documentation for the libraries themselves will still refer to them as "Socket Tools" and "Win32 Tools" etc. the whole package of what was formerly "the licensed code" is now The Server Framework.

With the launch of I'm also cleaning up how you get hold of the free version of the framework. Back in 2002 I first wrote about my server development efforts over at and with those articles I gave away an early version of the framework. That code is still available, it's unsupported but it's still a great way to kick start your development efforts if you don't want to pay for a license for The Server Framework. You can now get hold of the latest free code, now known as The Free Framework, from the download page here as a single zip file. 

Something else that's a little new is WASP. I've been building custom application servers with The Server Framework for years now and so have my clients but sometimes people don't need a fully customised server solution. Sometimes you just need a robust networking layer that you don't need to worry about. WASP is a pluggable application server that's free for non-commercial use. WASP is, in effect, just another example server that ships with The Server Framework and if you have a license to The Server Framework then you can customise it and learn from it as you do all the other examples. The big difference with WASP is that you can also download the compiled binary and, due to its pluggable design, you can write your own business logic and simply plug it in to WASP. Let WASP take care of the 'highly scalable, high performance' part of networking whilst you get on with writing your server. As I said, WASP is free for non-commercial use and the idea is that if you're considering purchasing a license for The Server Framework then you might be able to get a pretty decent prototype up and running using WASP to evaluate the performance that you get from The Server Framework. Of course WASP is limited, but simply buying a license to The Server Framework gives you all the code that you need to remove those limits and customise your application server as required. You can download WASP from here. also includes some forums. Up until now I've dealt with all support and questions directly via email and that will continue. I thought it may be useful, especially for users of WASP or The Free Framework, to be able to discuss things publicly. So now you can. 

This blog will be in addition to my technical blog over at Rambling Comments. The stuff that I post here will always be directly related to developments in The Server Framework whereas the stuff over at Rambling Comments will be more technically diverse. 

So, on with the show...

Follow us on Twitter: @ServerFramework

About this Archive

This page is an archive of recent entries in the General category.

Development is the previous category.

New features is the next category.

I usually write about the development of The Server Framework, a super scalable, high performance, C++, I/O Completion Port based framework for writing servers and clients on Windows platforms.

Find recent content on the main index or look in the archives to find all content.