* Switched to the use of direct byte buffers for NIO operations
* Scoped the byte buffer to the receiver, so we don't constantly allocate new ByteBuffers and toss them aside. In conjunction with allocating direct buffers, this has a dramatic effect on allocations and Garbage Collection. (Direct buffers are allocated by the OS, outside of the GC's generation spaces)
* Added a constructor for the MessageReceiver to allocate it's receive buffer to the same size as the sockets underlying buffer.
* Fixed a bug in the NIO code where prior to throwing a NotEnoughDataException the position of the buffer wasn't being updated.
** Updated the handling code for NotEnoughDataExceptions to no longer rely on the position of the buffer (but rather look at the buffer limit, or the amount previously read into the buffer) -- which basically makes the above change unnecessary, but I'm paranoid.