Posts Tagged ‘TCP Server’
Multi client Asynchronous TCP Server
This post is based on a tracer I am currently working on. My current project requires a TCP server implementation where other client could establish communication and perform data processing. The server should be able to handle multiple request from client. I never did any work with TCP Listener, initial one hour struggled a lot to get it working.
First approach I took was kind of Server – Server communication. That means there is no client both system act as server, it’s bit complex but I created a working prototype in next couple of hours. Yes it is complex, client app needs lot of work to establish a connection.
I need the server more simple and less code for the client to establish connection. So I started searching for simple TCP based client server approach. I stumble upon this post, where the author does a multi client communication. I got a start for my second tracer, a true client server model. I modified it and removed looping construct and used Async model instead. You all can see the code below.
TCP Server
private static TcpListener _listener; public static void StartServer() { System.Net.IPAddress localIPAddress = System.Net.IPAddress.Parse("10.91.173.201"); IPEndPoint ipLocal = new IPEndPoint(localIPAddress, 8888); _listener = new TcpListener(ipLocal); _listener.Start(); WaitForClientConnect(); } private static void WaitForClientConnect() { object obj = new object(); _listener.BeginAcceptTcpClient(new System.AsyncCallback(OnClientConnect), obj); } private static void OnClientConnect(IAsyncResult asyn) { try { TcpClient clientSocket = default(TcpClient); clientSocket = _listener.EndAcceptTcpClient(asyn); HandleClientRequest clientReq = new HandleClientRequest(clientSocket); clientReq.StartClient(); } catch (Exception se) { throw; } WaitForClientConnect(); } }
Here I use a async wait approach rather than waiting in a loop. So whenever a client connect OnClientConnected will fire and it handover the request to Client Request handler. After that it will again go back to wait mode for the next request. The advantage of this approach, the application is responsive and less CPU intensive compare to the looping approach.
Let’s see the client request handler
public class HandleClientRequest { TcpClient _clientSocket; NetworkStream _networkStream = null; public HandleClientRequest(TcpClient clientConnected) { this._clientSocket = clientConnected; } public void StartClient() { _networkStream = _clientSocket.GetStream(); WaitForRequest(); } public void WaitForRequest() { byte[] buffer = new byte[_clientSocket.ReceiveBufferSize]; _networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer); } private void ReadCallback(IAsyncResult result) { NetworkStream networkStream = _clientSocket.GetStream(); try { int read = networkStream.EndRead(result); if (read == 0) { _networkStream.Close(); _clientSocket.Close(); return; } byte[] buffer = result.AsyncState as byte[]; string data = Encoding.Default.GetString(buffer, 0, read); //do the job with the data here //send the data back to client. Byte[] sendBytes = Encoding.ASCII.GetBytes("Processed " + data); networkStream.Write(sendBytes, 0, sendBytes.Length); networkStream.Flush(); } catch (Exception ex) { throw; } this.WaitForRequest(); }
}
Here also I converted the waiting in loop to Async wait model. The looping model causes a constant hike in CPU utilization. This post explain how to asynchronously read request from client.
That’s all the server side. The client side is shown below
public class TCPClient { System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient(); NetworkStream serverStream; public void ConnectToServer() { clientSocket.Connect("10.91.173.201", 8888); } public void SendData(string dataTosend) { if (string.IsNullOrEmpty(dataTosend)) return; NetworkStream serverStream = clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.ASCII.GetBytes(dataTosend); serverStream.Write(outStream, 0, outStream.Length); serverStream.Flush(); } public void CloseConnection() { clientSocket.Close(); }
public string ReceiveData() { StringBuilder message = new StringBuilder(); NetworkStream serverStream = clientSocket.GetStream(); serverStream.ReadTimeout = 100; //the loop should continue until no dataavailable to read and message string is filled. //if data is not available and message is empty then the loop should continue, until //data is available and message is filled. while (true) { if (serverStream.DataAvailable) { int read = serverStream.ReadByte(); if (read > 0) message.Append((char)read); else break; } else if (message.ToString().Length > 0) break; } return message.ToString(); } }
As you can see most of the function is very simple to understand except ReceiveData(). I haven’t concentrated much on the client side as client of the actual TCP server will not be a .NET one. I am not discarding the fact, I will refactor ReceiveData().