September 2, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Communicating over Sockets: Blocking vs. Unblocking

  • March 27, 2006
  • By Mark Strawmyer
  • Send Email »
  • More Articles »

Sample Socket Connection Pool

You know the 3rd party system allows socket connections to remain open. In an effort to optimize performance, it is desired to have a connection pool of sockets open to the 3rd party system similar in concept to a database connection pool. The trailing sample code will provide you with a simple connection pooling object for your use. It will handle open and closing connections appropriately.

Sample Client Connection Pool Class

Thanks to the release of .NET 2.0, creating a socket connection pool isn't as difficult as it would have been in the past. Generics have introduced much of the plumbing that is required to accomplish the task through the System.Collections.Generic.Queue<T> object. You'll treat your socket connection pool as if it is a queue where you get connections from the queue and put connections back into the queue when you're complete.

using System;using System.Collections.Generic;using System.Net;using System.Net.Sockets;namespace CodeGuru.SocketSample{   /// <summary>   /// Connection pool of sockets.   /// </summary>   public static class SocketConnectionPool   {      /// <summary>The maximum size of the connection pool.</summary>      private static readonly int POOL_SIZE = 20;      /// <summary>The default port number for the      /// connection.</summary>      private static readonly int DEFAULT_PORT = 8080;      /// <summary>Queue of available socket connections.</summary>      private static Queue<Socket> availableSockets =         new Queue<Socket>();      /// <summary>      /// Get an open socket from the connection pool.      /// </summary>      /// <returns>Socket returned from the pool or new socket      /// opened.</returns>      public static Socket GetSocket()      {         if (SocketConnectionPool.availableSockets.Count > 0)         {            Socket socket = null;            while( SocketConnectionPool.availableSockets.Count > 0 )            {               socket = SocketConnectionPool.availableSockets.Dequeue();               if (socket.Connected)               {                  return socket;               }            }         }         return SocketConnectionPool.OpenSocket();      }      /// <summary>      /// Return the given socket back to the socket pool.      /// </summary>      /// <param name="socket">Socket connection to return.</param>      public static void PutSocket(Socket socket)      {         if (SocketConnectionPool.availableSockets.Count <             SocketConnectionPool.POOL_SIZE)         {            if (socket != null)            {               if (socket.Connected)               {                  // Set the socket back to blocking and enqueue                  socket.Blocking = true;                  SocketConnectionPool.availableSockets.Enqueue(socket);               }            }         }         else         {            // Number of sockets is above the pool size, so just            // close it.            socket.Close();         }      }      /// <summary>      /// Open a new socket connection.      /// </summary>      /// <returns>Newly opened socket connection.</returns>      private static Socket OpenSocket()      {         IPHostEntry localMachineInfo  = Dns.GetHostEntry("127.0.0.1");         IPHostEntry remoteMachineInfo = Dns.GetHostEntry("127.0.0.1");         IPEndPoint serverEndpoint =            new IPEndPoint( remoteMachineInfo.AddressList[0],                            SocketConnectionPool.DEFAULT_PORT);         IPEndPoint myEndpoint =            new IPEndPoint( localMachineInfo.AddressList[0], 0);         Socket socket =            new Socket( myEndpoint.Address.AddressFamily,                        SocketType.Stream, ProtocolType.Tcp);         socket.Connect(serverEndpoint);         return socket;      }   }}

Blocking vs. Unblocking

Now that you have your sample server and connection pool, you can create your client. A common stumbling block working with sockets and the main point of this article is blocking vs. unblocking sockets. Many examples demonstrate the use of blocking sockets, but don't really describe the behavior as blocking; this causes confusion. Blocking is where the receiving party blocks all activity while it waits to receive input from the socket. Sounds logical enough, but there are issues when the sending party is sending variant output and the receiver doesn't know all information has been sent.

Blocking Socket Sample

The following sample demonstrates the use of blocking sockets. You have to create a byte array of a specified length to read in the input. The byte array is a fixed size, so it may take multiple reads to read all of the input back from the socket connection. Thus, you do the Receive() method in a loop until all of the input is read from the socket. Here is some example code to illustrate the point.

Socket socket = null;try{   // Send the request   socket = SocketConnectionPool.GetSocket();   socket.Send(System.Text.Encoding.ASCII.GetBytes("<uptime></uptime>"));   // Read the response on a non-blocking socket   System.Text.StringBuilder output = new System.Text.StringBuilder();   byte[] buffer = new byte[256];   int bytesRead = 0;   string bufferString = "";   do   {      bytesRead = socket.Receive(buffer, buffer.Length, 0);      bufferString = System.Text.Encoding.ASCII.GetString(buffer);      output.Append(bufferString);   }   while (bytesRead > 0);   // Display the response   Console.WriteLine("Output: " + output.ToString());}finally{   SocketConnectionPool.PutSocket(socket);}

If you run this example, you will proceed through the loop a number of times based on the size of the output you are returning from the sample server. With the sample provided, it should only take a single read. However, the loop will try a second read and get stuck on the Receive method. That occurs because the server has stopped sending bytes, but the client is blocking and doesn't have any way to know the server is actually done sending. You could set the timeout on the client connection to a low interval, but that is not ideal in case the request takes a bit to respond. The server could be made to close the connection to indicate when it is done, but in this sample the server is a 3rd party and outside your control.

Unblocking Socket Sample

The following sample code demonstrates the use of a nonblocking socket. It gets around the prior issue where the client ends up in an indefinite state of waiting on a response. The key difference is in the Receive method. The nonblocking version will return immediately from the receive call, whereas the prior version would wait indefinitely for output. The nonblocking call to Receive will read whatever is available on the socket at that point in time. Thus, you'll read a little bit differently. You'll read in an infinite loop until the desired end tag is located from the XML. If something happens along the way, such as the server shutting down, the read will error out anyway and break the loop.

Socket socket = null;try{   // Send the request   socket = SocketConnectionPool.GetSocket();   socket.Send(System.Text.Encoding.ASCII.GetBytes("<uptime></uptime>"));   // Read the response on a non-blocking socket   System.Text.StringBuilder output = new System.Text.StringBuilder();   string bufferString = "";   socket.Blocking = false;   while (true)   {      if (socket.Poll(1000, SelectMode.SelectRead))      {         byte[] buffer = new byte[socket.Available];         socket.Receive(buffer, SocketFlags.None);         bufferString = System.Text.Encoding.ASCII.GetString(buffer);         output.Append(bufferString);      }      // Check if we've received the entire response      if (bufferString.IndexOf("</uptime>") != -1) break;   }   // Display the response   Console.WriteLine("Output: " + output.ToString());}finally{   SocketConnectionPool.PutSocket(socket);}

Other Considerations

There is additional functionality that could be added to this approach to make it more usable. An object model could be developed. You could establish a base class from which all business methods will inherit. A communicator class can be created to accept types based on the base business method class. The communicator could serialize the objects down to XML, send the XML across to the 3rd party system, read the XML response back from the 3rd party, and deserialize back into objects. That would simplify the process of sending requests and allow for additional business methods to be added at will.

Future Columns

The next column has yet to be determined. If you have something in particular that you would like to see explained, please e-mail me at mstrawmyer@crowechizek.com.

About the Author

Mark Strawmyer, MCSD, MCSE, MCDBA is a Senior Architect of .NET applications for large and mid-size organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design, and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the third year in a row. You can reach Mark at mstrawmyer@crowechizek.com.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel