I talked some time ago about a library I made to take advantage of the kernel network events. I now release it and explain how to use it. It can help people to do some little network software without knowing where to start from.

I built it for network servers made to communicate with remotely connected embedded chips. I wanted to be able to always stay in touch with a huge number of chips without any real cost. So, my very personal goal was to built a server network layer for massive M2M applications.

I also made a little web server with it supporting Keep-Alive and partial file download (with the Range header) and an other little library to send serialized objects.

I made this little network library to accomplish two main goals :

  • Simplify network server development
  • Be able to support a lot of connections

It is actually able to support a lot of connections : On a little Linux server using Mono (with 512 MB memory with swap deactivated), I easily managed to listen to 60 000 simultaneous connections without consuming more than 40% of the server’s memory.

And it allows to create network servers in only few line of code :

using System;
using System.Collections.Generic;
using System.Text;
using SoftIngenia.NetEventServer;
 
namespace TestServer {
 
    /// <summary>
    /// My little server
    /// </summary>
    class MyServer {
 
        public static String BytesToString( Byte[] data ) {
            var sb = new StringBuilder();
            sb.Append( String.Format( "[ {0} ] {{ ", data.Length ) );
            for ( int i = ; i < data.Length; ++i )
                sb.Append( String.Format( " 0x{0:X02}", data[ i ] ) );
            sb.Append( " }" );
            return sb.ToString();
        }
 
        /// <summary>
        /// My server view of the client
        /// </summary>
        class MyClient {
            public MyClient( uint id ) {
                Id = id;
            }
 
            public uint Id { get; private set; }
 
            public int NbMessagesReceived { get; set; }
 
            public void Treat( byte[] data ) {
                Console.WriteLine( "{0}.Treat( {1} );", this, BytesToString( data ) );
                NbMessagesReceived++;
            }
 
            public override string ToString() {
                return String.Format( "Client{{Id={0}}}", Id );
            }
        }
 
        private readonly TcpEventServer _server;
        private readonly Dictionary<uint, MyClient> _clients = new Dictionary<uint, MyClient>();
 
        public MyServer( int portNumber ) {
            _server = new TcpEventServer( portNumber );
            _server.ClientConnected += server_ClientConnected;
            _server.ClientDisconnected += server_ClientDisconnected;
            _server.BinaryDataReceivedFromClient += server_BinaryDataReceivedFromClient;
        }
 
        public void StartListening() {
            _server.StartListening();
        }
 
        void server_BinaryDataReceivedFromClient( uint clientId, byte[] data ) {
            _clients[ clientId ].Treat( data );
        }
 
        void server_ClientDisconnected( uint clientId ) {
            Console.WriteLine( "Client {0} disconnected !", clientId );
            _clients.Remove( clientId );
        }
 
        void server_ClientConnected( uint clientId ) {
            Console.WriteLine( "Client {0} connected from {1} !", clientId, _server.RemoteEndPoint( clientId ) );
            _clients.Add( clientId, new MyClient( clientId ) );
        }
 
 
    }
 
    class Program {
        static void Main() {
            var myserver = new MyServer( 3000 );
            myserver.StartListening();
 
            Console.WriteLine( "Listening..." );
            Console.ReadLine();
        }
    }
}

This app launched gives you something like that :

Listening...
Client 1 connected from 127.0.0.1:53792 !
Client{Id=1}.Treat( [ 5 ] { 0x68 0x65 0x6C 0x6C 0x6F } ); // "hello"
Client{Id=1}.Treat( [ 2 ] { 0x0D 0x0A } ); // '<CR>' '<LF>'
Client 1 disconnected !

The library also enables you to receive data as text. You just have to subscribe to the ReceivedLine event. There’s no performance cost if you don’t subscribe to the event.

For network server, you still need to do some frame recognition. I usually instantiate a FrameParsing class into every client on the server side.

You can download the NetEventServer library with its XML and PDB files.