Click here to Skip to main content
15,867,299 members
Articles / Programming Languages / C#

WCF Killer

Rate me:
Please Sign up or sign in to vote.
4.92/5 (22 votes)
11 Feb 2011CPOL4 min read 72.5K   1.1K   68   35
A simple high performance drop-in TCP protocol handler for client server communications with POCO objects and no messy proxy classes like WCF.

Image 1

Introduction

This is a piece of code that I have been using for a long time, which is simple to use, doesn't impose any additional work, and gets the job done for client server communications using the TCP protocol. You just include a single file in your project and get all the benefits.

Kudos to Yuen Chiu So for writing the original article found here (dotnettcp.aspx). The original article only handled strings; my article extends that to a level which you can use in your own client server application which must transfer the detailed objects of data. I have also tweaked and tested the code to get the maximum performance and stability out of it (see the performance test section).

Background

This code came about after using named pipe communication for a long time and having the following problems, although arguably named pipes are faster at data transfer:

  • Named pipes require authentication on connection to a computer, which is very limiting in non-domain computers and requires the user to enter a valid system user and password on the destination computer to even work.
  • The named pipe implementation I was using was very large, code wise.

So for the above reasons, I set about creating a replacement which would fit the following requirements:

  • Simple to use in code, with minimal configuration.
  • Multi-threaded so it can scale to hundreds of simultaneous users.
  • Does not impose additional code "proxies" and "contracts" and should work with normal serializable objects.
  • Does not require computer level authentication, which is implicit in using the TCP protocol as it is handled at a lower level than the OS (unlike named pipes).
  • Flexibility to implement your own authentication on top of it.
  • Handle large data transfer objects, e.g., 3 MB data packets.

The test application

testserver.png

Run the solution, and you will get a command line application like in the picture above. Press the 'S' key for server mode, 'C' key for client mode, and anything else for automatic mode which will start sending requests to the server. The application is hard coded to send and receive on the 127.0.0.1 IP address which is the local system; you can change this to test on a real network with different computers.

The data.cs file contains the sample POCO data object which is hard coded to a 3 MB size; you can change this to test smaller and larger data packets (see the performance test section).

Using the code

To use the code, first you must create your data packets like the ones below:

C#
[Serializable()]
public class Packet
{
    public Packet()
    {
        data = new byte[3*1024*1024]; // 3 mega byte
    }
    public byte[] data { get; set; }

    public string Message { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public Guid SessionGuid { get; set; }

    public new string ToString()
    {
        return Message;
    }
}

[Serializable()]
public class ReturnPacket
{
    public bool OK { get; set; }
    public string Message { get; set; }
}

As you can see, the data structures are normal classes and not proxies; you also must put the Serializble attribute on the class so the .NET serializer can work with it.

For the server code, you do the following:

C#
NetworkServer ns = new NetworkServer(99, new ProcessPayload(serverprocess));
// will listen on port 99

ns.Start();

private static object serverprocess(object data)
{
    Packet dp = data as Packet;
    if (dp != null)
        return HandlePacket(dp);
   
    Console.WriteLine("message not recognized");
    return new ReturnPacket();
}

private static object HandlePacket(Packet dp)
{
    ReturnPacket ret = new ReturnPacket();
    if (dp.SessionGuid == Guid.Empty)
    {
        // Authenticate username and password possibly with LDAP server
    }
    else
    {
        // check sessionguid valid -> if not return failed
    }
    ret.OK = true;
    ret.Message = "your msg : " + dp.Message + "\r\nreturn from server " + DateTime.Now;
    return ret;
}

As you can see, it is pretty straightforward and simple.

For the client side, you do the following:

C#
NetworkClient nc = new NetworkClient("127.0.0.1", 99);
// send to local host on port 99

nc.Connect();
Packet p = new Packet();
ReturnPacket ret = nc.Send(p) as ReturnPacket;

What is up to you

The following is up to you to implement yourself as you see fit for your own application:

  • Data Packet Definitions: what you want to send over the wire
  • Authentication: handling authentication is up to you if you need it
  • Session Management: related to authentication is session management

Performance tests

Here is the performance test results done on an AMD K625 1.5ghz, 4GB RAM, Windows 7 Home, win rating of 3.9 Notebook (CPU usage above 88%):

Number of simultaneous clientsData packet sizeChunk sizeRequest in 10 secs
5~12kb32kb12681
5~12kb16kb12291
5~12kb4kb11089
5~3mb4kb141
5~3mb16kb207
5~3mb32kb220

As you can see, the best performance is with a CHUNK_SIZE of 32 KB for both small and large data packets. You can go higher, e.g., 64 KB, but you get diminishing returns, and possibly (I don't know for sure), you may have problems with some switches and routers in the network as they might block large packet sizes.

Points of interest

I have put the network server code in a NETSERVER conditional compilation block so you will have to add that to your project definition. There is a Config class in the NetWorkClient.cs file which has some predefined options that I have tweaked to maximum performance; one note worthy option is NUM_OF_THREADS which is how many threads the server creates to handle a request. The default is 10, which should be enough for most applications; I have used it for handling 50+ clients applications in real world circumstances.

What you can do at home or further directions

Below is a list of possibilities you can do at home if you feel adventurous:

  • Progress Events: events to publish the progress of data for the client application to hook on to and display UI for.
  • Encrypted Communication: using SslStream instead of NetworkStream for encrypted data transfer.
  • LDAP Authentication of User: check the username and password embedded in the packet with an LDAP server (see the comments in the test app).
  • Session Management: handle client sessions and authenticated connections (see the comments in the test app).
  • Maybe replace BinarySerializer: for greater performance, you could look at the protocol serializer from Google which is incredibly fast and compact.

History

  • Initial release: Feb. 12, 2011.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect -
United Kingdom United Kingdom
Mehdi first started programming when he was 8 on BBC+128k machine in 6512 processor language, after various hardware and software changes he eventually came across .net and c# which he has been using since v1.0.
He is formally educated as a system analyst Industrial engineer, but his programming passion continues.

* Mehdi is the 5th person to get 6 out of 7 Platinum's on Code-Project (13th Jan'12)
* Mehdi is the 3rd person to get 7 out of 7 Platinum's on Code-Project (26th Aug'16)

Comments and Discussions

 
Questionread from network device Pin
george498620-Jan-14 18:09
professionalgeorge498620-Jan-14 18:09 
AnswerRe: read from network device Pin
Mehdi Gholam20-Jan-14 18:26
Mehdi Gholam20-Jan-14 18:26 
GeneralRe: read from network device Pin
george498620-Jan-14 22:36
professionalgeorge498620-Jan-14 22:36 
GeneralRe: read from network device Pin
Mehdi Gholam20-Jan-14 22:51
Mehdi Gholam20-Jan-14 22:51 
GeneralRe: read from network device Pin
george498620-Jan-14 23:02
professionalgeorge498620-Jan-14 23:02 
GeneralRe: read from network device Pin
Mehdi Gholam20-Jan-14 23:18
Mehdi Gholam20-Jan-14 23:18 
GeneralMy vote of 5 Pin
Manfred Rudolf Bihy28-Sep-13 12:14
professionalManfred Rudolf Bihy28-Sep-13 12:14 
GeneralRe: My vote of 5 Pin
Mehdi Gholam28-Sep-13 20:43
Mehdi Gholam28-Sep-13 20:43 
GeneralRe: My vote of 5 Pin
Manfred Rudolf Bihy29-Sep-13 1:49
professionalManfred Rudolf Bihy29-Sep-13 1:49 
Question"Maybe replace BinarySerializer" Pin
LGSon229-Aug-13 20:26
LGSon229-Aug-13 20:26 
AnswerRe: "Maybe replace BinarySerializer" Pin
Mehdi Gholam29-Aug-13 20:39
Mehdi Gholam29-Aug-13 20:39 
GeneralRe: "Maybe replace BinarySerializer" Pin
LGSon229-Aug-13 22:22
LGSon229-Aug-13 22:22 
QuestionVote 5 Pin
Shabana Parveen6-Mar-13 18:49
professionalShabana Parveen6-Mar-13 18:49 
AnswerRe: Vote 5 Pin
Mehdi Gholam6-Mar-13 19:21
Mehdi Gholam6-Mar-13 19:21 
QuestionUsing the code Pin
abacrotto11-Oct-12 13:08
abacrotto11-Oct-12 13:08 
AnswerRe: Using the code Pin
Mehdi Gholam11-Oct-12 17:11
Mehdi Gholam11-Oct-12 17:11 
GeneralRe: Using the code Pin
abacrotto12-Oct-12 0:34
abacrotto12-Oct-12 0:34 
GeneralRe: Using the code Pin
Mehdi Gholam12-Oct-12 0:39
Mehdi Gholam12-Oct-12 0:39 
GeneralAsync communication form server to client Pin
Ferdinando Santacroce16-Feb-11 4:47
Ferdinando Santacroce16-Feb-11 4:47 
First of all, thank you for sharing! Smile | :)
I need to do some async communication from server to client.
This is my scenario: client send a packet with data, server get it and then starts to do some work; when finished, it send a packet with response to the client.
Do you think your project can do it?
Can you point me to the right way to modify your project?
Thanks! Smile | :)
Jesus

GeneralRe: Async communication form server to client Pin
Mehdi Gholam16-Feb-11 20:08
Mehdi Gholam16-Feb-11 20:08 
QuestionRe: Async communication form server to client Pin
Ferdinando Santacroce16-Feb-11 20:40
Ferdinando Santacroce16-Feb-11 20:40 
GeneralMy vote of 3 Pin
Paulo Zemek12-Feb-11 2:43
mvaPaulo Zemek12-Feb-11 2:43 
GeneralRe: My vote of 3 Pin
Mehdi Gholam12-Feb-11 4:34
Mehdi Gholam12-Feb-11 4:34 
GeneralRe: My vote of 3 Pin
Paulo Zemek13-Feb-11 13:48
mvaPaulo Zemek13-Feb-11 13:48 
GeneralRe: My vote of 3 Pin
Sergey Alexandrovich Kryukov30-Jun-12 16:07
mvaSergey Alexandrovich Kryukov30-Jun-12 16:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.