CodeGuru
Earthweb Search
Forums Wireless Jars Gamelan Developer.com
CodeGuru Navigation
Member Sign In
User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.
Biz Resources
Ecommerce Hosting
Dedicated Server Hosting
Data Recovery Services

jobs.internet.com

internet.commerce
Partners & Affiliates
Phone Cards
KVM over IP
Memory Upgrades
Promotional Pens
Laptops
Career Education
Corporate Awards
Car Donations
Home Improvement
Online Universities
Imprinted Promotions
SMS Gateway
Dental Insurance
Cell Phones


RSS Feeds

RSSAll

RSSVC++/C++

RSS.NET/C#

RSSVB

See more EarthWeb Network feeds

Home >> .NET / C# >> C# >> Network & Systems >> Sockets

Best Practices for Developing a Web Site: Checklists, Tips, Strategies & More. Download Exclusive eBook Now.

Asynchronous Socket Programming in C#: Part II
An advanced C# socket program example with a single server and multiple simultanneous clients
Rating:

Jayan Nair (view profile)
October 6, 2005

Environment:  C#, Windows

Motivation for This Article

After the original article on Asynchronous Socket Programming in C# was published by CodeGuru, I received numerous responses from interested readers. Most of them asked for additional features that were missing in the original example. The original article was intended to show a simplistic example for asynchronous socket programming. To keep the simplicity of the original example, instead of modifying it, I am providing a more comprehensive example by adding the features requested by the readers.

Requested Features Added


(continued)



Web Devs:
Moonlight as a Game Developer and Win Cool Prizes by Accepting the RIA Run Challenge

Now, your mission--should you choose to accept: Take your shot at gaming stardom if you think you might have what it takes to build a cool RIA game and you could win an Xbox 360 or other fabulous prizes. Hurry! You only have until May 15, 2008 to enter. »

 
Article:
Leveraging Your Flash Development with Silverlight

You're not giving up Flash any time soon (and we don't blame you.) But if you could get your Flash application working in Silverlight, why wouldn't you? We show you the tools and techniques required to have your rockin' Flash application rolled for Silverlight. Learn more here. »

 
Article:
What Does it Take to Build the Best RIA?

With the proliferation of Rich Interactive Application (RIA) platform choices out there, you no longer have to take a one-size-fits-all approach to developing your next RIA application. Knowing the strengths (and weaknesses) of each platform can help you to decide the best RIA for your next application. »

 

This example includes modifications to support the following features:

  1. How to support an unlimited number of clients
  2. How to find which client sent a particular message
  3. How to reply or send messages to specific clients
  4. How to find when a particular client is disconnected
  5. How to get the list of all connected clients at any given time
  6. Are variables safe in AsyncCallback methods? What about thread synchronization? [Updated on 02/01/05]

Other Enhancements

  1. On the server and client code, the receive buffer size is increased to 1024 instead of a single byte for more efficiency.
  2. Cleanup code is added after a client is disconnected.

Screen shot of Socket Server:

Screen shot of Socket Client:

How to Support an Unlimited Number of Clients

This was an easy feature to add. In the original article, an array of Socket objects was used to store the references to the worker sockets. This is now modified to use an ArrayList as shown in the following code. (A HashTable also would have worked if you wanted to use a string instead of an index to track the connected clients.)

Note: If you want to run your server for an infinite duration, there is the possibility of overflow of the integer value of the m_clientCount variable. In such scenarios, you may want to reconsider using this numbering scheme for clients. This example will still work on such scenarios, as long as you don't number your clients. But, this issue goes beyond the scope of this article.
// An ArrayList is used to keep track of worker sockets that are
// designed to communicate with each connected client
private System.Collections.ArrayList m_workerSocketList =
   new System.Collections.ArrayList();
// The following variable will keep track of the cumulative
// total number of clients connected at any time
private int m_clientCount = 0;

How to Find Which Client Sent a Particular Message

When multiple clients are connected, you may need to differentiate between the messages received from different clients. Also, there may be a reason to send a message to a particular client.

You could solve this problem by keeping track of each client by assigning them a serially incremented number as soon as they are connected to the server. Here is the code that does that:

public void OnClientConnect(IAsyncResult asyn)
{
   try
   {
      // Here we complete/end the BeginAccept() asynchronous call
      // by calling EndAccept(), which returns the reference to a
      // new Socket object
      Socket workerSocket = m_mainSocket.EndAccept (asyn);
      // Now, increment the client count for this client
      ++m_clientCount;
      // Add the workerSocket reference to the ArrayList
      // We will use (clientNumber - 1) as the index to access
      // this socket in the future
      m_workerSocketList.Add(workerSocket);
      //........
      // Let the worker Socket do the further processing for the
      // just-connected client
      WaitForData(workerSocket, m_clientCount);
      //........

Inside the WaitForData() function, you will make the actual asynchronous call to receive the data from the client as shown below:

public void WaitForData(System.Net.Sockets.Socket soc,
                        int clientNumber)
{
   try
   {
      if( pfnWorkerCallBack == null )
      {
         // Specify the callback function that is to be invoked when
         // there is any write activity by the connected client
         pfnWorkerCallBack = new AsyncCallback (OnDataReceived);
      }
      SocketPacket theSocPkt = new SocketPacket (soc, clientNumber);
      // Start receiving any data written by the connected client
      // asynchronously
      soc.BeginReceive (theSocPkt.dataBuffer, 0,
      theSocPkt.dataBuffer.Length,
      SocketFlags.None,
      pfnWorkerCallBack,
      theSocPkt);
      //........

In the above code, the user-defined class SocketPacket is the most critical item. As you can see, an object of this class is the last parameter passed to the asynchronous function call BeginReceive(). This object can contain any information that you find useful; it can be used later, when you actually receive the data from the client. You send (1) the worker socket object and (2) the index number of the client packaged inside this object. You will retrieve them back when you actually receive the data from a particular client.

Given below is the definition of the SocketPacket class.

public class SocketPacket
{
   // Constructor that takes a Socket and a client number
   public SocketPacket(System.Net.Sockets.Socket socket,
                       int clientNumber)
   {
      m_currentSocket = socket;
      m_clientNumber  = clientNumber;
   }
   public System.Net.Sockets.Socket m_currentSocket;
   public int m_clientNumber;
   // Buffer to store the data sent by the client
   public byte[] dataBuffer = new byte[1024];
}

In the above code, the SocketPacket class contains the reference to a socket, a data buffer of size 1024 bytes, and a client number. This client number will be available when you actually start receiving data from a particular client. By using this client number, you can identify which client actually sent the data.

To demonstrate this in the example code, the server will echo back to the client (after converting to upper case) the received message, using the correct socket object.

How to Reply or Send Messages to Specific Clients

You might have figured out this already. This is very simple to implement. Because the SocketPacket object contains the reference to a particular worker socket, you just use that object to reply to the client. Additonally, you also could send any message to any particular client by using the worker socket object stored in the ArrayList.

How to Find when a Particular Client is Disconnected

This is a bit harder to address. There may be other elegant ways to do this, but here is a simple way.

When a client is disconnected, there will be a final call to the OnDataReceived() function. If nothing in particular is done, this call will throw a SocketException. What you can do here is to look inside this exception and see whether this was triggered by the "disconnection" of a client. For this, you will look at the error code inside the exception object and see whether it corresponds to 10054. If so, you will do the required action corresponding to the client disconnection. Here again, the SocketPacket object will give you the index number of the client that was disconnected.

catch(SocketException se)
{
   if(se.ErrorCode == 10054)    // Error code for Connection reset
                                // by peer
   {
      string msg = "Client " + socketData.m_clientNumber +
                   " Disconnected" + "\n";
      richTextBoxReceivedMsg.AppendText(msg);

      // Remove the reference to the worker socket of the closed
      // client so that this object will get garbage collected
      m_workerSocketList[socketData.m_clientNumber - 1] = null;
      UpdateClientList();
   }
   else
   {
      MessageBox.Show (se.Message );
   }
}

How to Get the List of All Connected Clients at Any Given Time

To show this, a dynamic list is displayed on the server GUI that will be updated (see the UpdateClientList() function) whenever a client is connected or disconnected.

Are Variables Safe in AsyncCallback Methods? What About Thread Synchronization?

This is a very valid question. For simplicity, I ignored this aspect in the first part of this article. Asynchronous programming using asynchronous delegates is just a matter of convenience. When you use asynchronous calls, you should be aware that, behind the scenes, you are actually using threads to achieve the asynchronous nature of these calls.

The following picture shows a simple illustration of the interplay of threads involved in this example.

In the above picture, the item labeled (1) is the main GUI thread that starts when you start the Server application. The thread labeled (2) starts whenever any client tries to connect to the socket. The thread labeled (3) spawns when there is any write activity by any one of the connected clients.

In the example code, the asynchronous functions OnClientConnect() and OnDataReceived() are called by threads other than the main GUI thread. Any other functions called inside these two functions are also invoked by threads other than the main GUI thread.

Threading issues to consider

  1. Shared variables

    Any shared variables that you modify inside the shared code mentioned above must be protected by synchronization structures. In this example, the shared variables you modify within the shared code are m_clientCount and m_workerSocketList.

    You can use very simple strategies to protect these variables. The m_clientCount variable is an integer variable and hence can be incremented by using the static method within the Interlocked class as shown below:

    // Now increment the client count for this client
    // in a thread safe manner
    Interlocked.Increment(ref m_clientCount);
    

    Similarly, you can protect the m_workerSocketList member variable from modification by multiple threads at the same time, by creating a Synchronized ArrayList as shown below:

    private System.Collections.ArrayList m_workerSocketList =
       ArrayList.Synchronized(new System.Collections.ArrayList());
    
  2. Modifying the GUI
  3. The main GUI thread actually owns the GUI controls. Hence, in production code, it is not recommended or advisable to access or modify any of the GUI controls by threads other than the main thread. When you need to update the GUI, you should make the main thread do it for you as shown in the following code:

    // This method could be called by either the main thread or
    // any of the worker threads
    private void AppendToRichEditControl(string msg)
    {
       // Check to see if this method is called from a thread
       // other than the one created the control
       if (InvokeRequired)
       {
          // We cannot update the GUI on this thread.
          // All GUI controls are to be updated by the main (GUI)
          // thread.
          // Hence, we will use the invoke method on the control
          // that will be called when the Main thread is free
          // Do UI update on UI thread
          object[] pList = {msg};
          richTextBoxReceivedMsg.BeginInvoke(new
             UpdateRichEditCallback(OnUpdateRichEdit), pList);
       }
       else
       {
       // This is the main thread which created this control,
       // hence update it directly
          OnUpdateRichEdit(msg);
       }
    }
    
    // This UpdateRichEdit will be run back on the UI thread
    // (using System.EventHandler signature so we don't
    // need to define a new delegate type here)
    private void OnUpdateRichEdit(string msg)
    {
       richTextBoxReceivedMsg.AppendText(msg);
    }
    

Acknowledgement

Part II of this article was developed to address the questions and comments I received from readers after publishing Part I of this article. The example programs used in Part I which are further enhanced and extended for Part II, are influenced by the article on Socket Programming in C# by Ashish Dhar.

Final Comments

Network programming is a very interesting topic. The C# language provides you with all the tools necessary to quickly develop networked applications. Compared to C++, Java and C# have a richer set of programming APIs, which will eliminate most of the complexities previously associated with network programming. This example incorporates all the features that the readers requested. Even then, use this example only as a learning tool. As you learn more about socket programming, you will realize the necessity to add thread synchronization constructs as well see the opportunities for further optimization, to solve the problem at your hand. Good luck with your learning and thanks for reading.

About the Author
Jayan Nair is a Senior Software Engineer with 8+ years of experience working with cutting edge software technologies. Currently he is developing the next generation software applications for the telecommnunications testing industry. Jayan's passions: Object Oriented software design and developing reusable software components. His motto: "if the software you write is not reusable, you are not writing software, but hardware instead". Jayan finished his Masters degree in Computer Science from Virginia Tech, Blacksburg, VA. His expertise includes, C, C++, Java, J2EE, Visual Basic, C#, ASP.NET and distributed applications. He is also a Sun Certified Programmer for the Java Platform (SCPJ). You can contact him at jnair1998@hotmail.com.

Downloads

  • async_client_server_II_exe.zip - Windows executable files
  • async_client_server_II_src.zip - C# Source Code

    Tools:
    Add www.codeguru.com to your favorites
    Add www.codeguru.com to your browser search box
    IE 7 | Firefox 2.0 | Firefox 1.5.x
    Receive news via our XML/RSS feed

    Is it time to make your move to the multi-threaded and parallel processing world? Find out!
    Whitepaper: Enterprise Information Integration--Deployment Best Practices for Low-Cost Implementation
    Guide to Developing a Web Site. Best Practices, Tips and Strategies. Download Exclusive eBook Now.
    Data Sheet: IBM Information Server Blade
    Whitepaper: XML Processing in Applications--Take the Next Step


  • RATE THIS ARTICLE:   Excellent  Very Good  Average  Below Average  Poor  

    (You must be signed in to rank an article. Not a member? Click here to register)

    Latest Comments:
    How can I check the example works across the internet? - Gordon Pagan (02/13/2008)
    size of packet - fing (12/28/2007)
    receive packets on server side - fing (12/22/2007)
    receive packets on server side - fing (12/22/2007)
    Read more than 1024 bytes - robcrowe (12/03/2007)

    View All Comments
    Add a Comment:
    Title:
    Comment:
    Pre-Formatted: Check this if you want the text to display with the formatting as typed (good for source code)



    (You must be signed in to comment on an article. Not a member? Click here to register)


    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

    Solutions
    Whitepapers and eBooks
    Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
    Microsoft Article: 7.0, Microsoft's Lucky Version?
    Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Windows Server 2008
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES