Click here to Skip to main content
12,509,899 members (53,242 online)
Click here to Skip to main content
Add your own
alternative version

Stats

462.8K views
35.2K downloads
136 bookmarked
Posted

Multithreaded Chat Server

, 31 Jan 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
This is a simple multithreaded chat server, intended for people to learn Socket programming and Threads in C#.

Sample Image - Chat.jpg

Introduction

I started writing this application to learn Socket programming, Threads, and UI controls in C#. But in the process, I learned more than that. We would go step by step and will try to cover all important aspects of this application. But before we begin, I'd like to set some expectations about the application. This application demonstrates how multiple clients can connect to a single server and communicate to the server. However, at this point, clients cannot communicate with each other. That would be the next step for this application.

Using the code

What do you need to get started with a multithreaded chat application? Threads and Sockets.

Following is how the application starts and how it works:

  1. As soon as the application is started, the main thread is spawned by the system.
  2. The main thread then spawns a thread which keeps listening on a given port.
  3. As soon as there is any connection request from a client, a connection is established. After the connection gets established, another thread is spawned to open a dialog box for chatting with clients.
  4. For every connection to a client, a new thread is spawned. Hence, if there are three clients connected to the server, then the total active threads will be five, one main thread, one thread for listening, and one each for chatting with the connected clients.

Now, let's look at what each thread, that corresponds to a client connect, does:

  1. Calls the asynchronous BeginReceive method. A callback method is passed a parameter. This callback method is called when any data is received on that socket.
  2. When data is received on a socket, the data is read and displayed on the rich text box of the chat dialog. However, if a SocketException is raised, then the connection is closed, as this means that the client has asked to close the connection.
  3. When the Send button is clicked, data is sent to client.

Huh! Looks pretty simple. Now, let's look at some concepts in C# that are required to understand the implementation.

1. How does asynchronous receive work?

.NET framework's Socket class provides a BeginReceive method to receive data asynchronously, i.e., in a non-blocking manner. The BeginReceive method has the following signature:

public IAsyncResult BeginReceive( byte[] buffer, int offset, int size, 
   SocketFlags socketFlags, AsyncCallback callback, object state );

The way the BeginReceive function works is that, you pass the function a buffer and a callback function (delegate) which will be called whenever data arrives. The callback method is called by the system when data is received on the given socket. This method is called using a separate thread (internally spawned by the system). Hence this operation is asynchronous and non-blocking.

Now, where exactly will be the received data? It will be in the buffer that was passed in the BeginReceive method. But before you read the data, you should know the number of bytes that has been received. This is achieved by calling the EndReceive method of the Socket class.

The BeginReceive call is completed only after the EndReceive method of the Socket. The following code will clear what has been explained in the above paragraphs:

BeginReceive call is made:

// Create the state object. 
StateObject state = new StateObject(); 
state.workSocket = connectedClient.Client; 

//Call Asynchronous Receive Function 
connectedClient.Client.BeginReceive(state.buffer, 0, 
  StateObject.BufferSize, 0,new AsyncCallback(OnReceive), state);

Callback function when data is received on the Socket:

public void OnReceive(IAsyncResult ar) 
{ 
  String content = String.Empty; 
  // Retrieve the state object and the handler socket  
  // from the asynchronous state object. 

  StateObject state = (StateObject)ar.AsyncState; 
  Socket handler = state.workSocket; 
  int bytesRead; 
  if (handler.Connected) 
  { 
    // Read data from the client socket. 

    try  
    { 
      bytesRead = handler.EndReceive(ar); 
      if (bytesRead > 0) 
      { 
        // There might be more data, so store the data received so far.
        state.sb.Remove(0, state.sb.Length); 
        state.sb.Append(Encoding.ASCII.GetString( 
        state.buffer, 0, bytesRead)); 
        
        // Display Text in Rich Text Box  
        content = state.sb.ToString(); 
        SetText(content); 
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 
                             0,new AsyncCallback(OnReceive), state); 
      } 
    } 
    catch (SocketException socketException) 
    { 
      //WSAECONNRESET, the other side closed impolitely 
      if (socketException.ErrorCode == 10054 || 
         ((socketException.ErrorCode != 10004) && 
         (socketException.ErrorCode != 10053))) 
      { 
         // Complete the disconnect request.
         String remoteIP = 
           ((IPEndPoint)handler.RemoteEndPoint).Address.ToString(); 
         String remotePort = 
           ((IPEndPoint)handler.RemoteEndPoint).Port.ToString(); 
         this.owner.DisconnectClient(remoteIP, remotePort); 
         handler.Close(); 
         handler = null; 
       } 
     } 
    // Eat up exception....Hmmmm I'm loving eat!!!  
    catch (Exception exception) 
    { 
      MessageBox.Show(exception.Message + "\n" + exception.StackTrace); 
    } 
  } 
}

2. How can you access a User Interface control (e.g., RichText Box) from a thread which is not an owner of that UI control?

Answer is, use Delegates.

If you look at the application, The rich text box that displays the chat message is created by the thread that creates the chat dialog box. Now, the chat data in the rich text box is updated by a thread that calls the callback function, OnReceive. This is a system spawned thread!

In order to access it, create a delegate as:

public delegate void SetTextCallback(string s);

Now, create a function to update the rich text box as:

private void SetText(string text) 
{ 
// InvokeRequired required compares the thread ID of the 
// calling thread to the thread ID of the creating thread. 
// If these threads are different, it returns true. 

  if (this.rtbChat.InvokeRequired) 
  { 
    SetTextCallback d = new SetTextCallback(SetText); 
    this.Invoke(d, new object[] { text }); 
  } 
  else 
  { 
    this.rtbChat.SelectionColor = Color.Blue; 
    this.rtbChat.SelectedText = "\nFriend: "+text; 
   } 
}

History

  • Updated on 12/13/2006 - Formatted article, and added a few details.
  • Updated on 01/31/2007 - Updated the sample client code and added validation to port the text box in server code.

License

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

Share

About the Author

Sidzone
Architect
United States United States
Sid works in one of the top IT consulting company, in Datawarehousing projects.
MS Technologies has always excited him. He codes in C# for fun.

Apart from keen interest in .NET, Sid loves playing cricket and has passion for photography.

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionHow do you rebuild the client? Pin
KW199131-Aug-15 0:36
memberKW199131-Aug-15 0:36 
QuestionCaution Pin
Stephen Chapman6-Jun-15 0:22
memberStephen Chapman6-Jun-15 0:22 
Questionhow can I send data to all my chat users? Pin
ikoko73-Dec-13 8:13
memberikoko73-Dec-13 8:13 
GeneralRe: how can I send data to all my chat users? Pin
Member 1109349827-Jul-15 9:35
memberMember 1109349827-Jul-15 9:35 
Question[My vote of 1] Be Neutral! Pin
Ashim Malgope19-Jul-13 6:00
professionalAshim Malgope19-Jul-13 6:00 
QuestionClient stand by mode. Pin
Meryem gömeç17-Jun-13 22:26
memberMeryem gömeç17-Jun-13 22:26 
Questionwhy does the UpdateClient's function not active ???? Pin
thanhdatbkfet10-Apr-13 0:59
memberthanhdatbkfet10-Apr-13 0:59 
QuestionParent and child forms Pin
Josip8417-Dec-12 23:42
memberJosip8417-Dec-12 23:42 
QuestionUse nonModal forms for chat windows Pin
Member 85973554-Aug-12 6:33
memberMember 85973554-Aug-12 6:33 
GeneralMerge Client and server? Pin
kiran.sr3ram10-Jul-12 23:22
memberkiran.sr3ram10-Jul-12 23:22 
BugException Pin
ashimloves4-Jun-12 0:16
memberashimloves4-Jun-12 0:16 
GeneralMy vote of 5 Pin
cscodes20-Feb-12 3:21
membercscodes20-Feb-12 3:21 
Questionhello Pin
mohandesmina25-Dec-11 10:57
membermohandesmina25-Dec-11 10:57 
GeneralMy vote of 4 Pin
Sabrina Adams21-Nov-11 0:00
memberSabrina Adams21-Nov-11 0:00 
GeneralMy vote of 4 Pin
muhammadmajd14-Oct-11 6:32
membermuhammadmajd14-Oct-11 6:32 
QuestionThis code is worthless clients talk to themselves Pin
yoru amama20-Jun-11 16:39
memberyoru amama20-Jun-11 16:39 
GeneralThanks Pin
nkt_pr12-Apr-11 2:21
membernkt_pr12-Apr-11 2:21 
GeneralMy vote of 1 Pin
mmmgedadads7-Mar-11 22:27
membermmmgedadads7-Mar-11 22:27 
GeneralMy vote of 1 Pin
mmmgedadads7-Mar-11 22:26
membermmmgedadads7-Mar-11 22:26 
GeneralMy vote of 1 Pin
mmmgedadads7-Mar-11 22:26
membermmmgedadads7-Mar-11 22:26 
GeneralMy vote of 1 Pin
mmmgedadads7-Mar-11 22:25
membermmmgedadads7-Mar-11 22:25 
GeneralThanks your code is great Pin
caracarogna1-Jan-11 23:12
membercaracarogna1-Jan-11 23:12 
GeneralRe: Thanks your code is great Pin
Josip8417-Dec-12 22:47
memberJosip8417-Dec-12 22:47 
QuestionCan Anybody plz tell me about hacking through .NET Framework Pin
jitenderkr22-Aug-10 20:21
memberjitenderkr22-Aug-10 20:21 
Questionexception error [modified] Pin
Mostafa__Salem11-Jul-09 3:14
memberMostafa__Salem11-Jul-09 3:14 
AnswerRe: exception error Pin
Battya Fonokk14-May-10 0:12
memberBattya Fonokk14-May-10 0:12 
Questionwhat about Syncronize Pin
Mostafa__Salem9-May-09 5:08
memberMostafa__Salem9-May-09 5:08 
GeneralSimulator to check TPS(Txn per Sec) Pin
Member 245269826-Mar-09 19:42
memberMember 245269826-Mar-09 19:42 
GeneralRouter problems... Pin
Sniper1674-Mar-08 13:48
memberSniper1674-Mar-08 13:48 
GeneralRe: Router problems... Pin
tung23816-Jul-10 17:31
membertung23816-Jul-10 17:31 
QuestionDoes it work with the internet ? Pin
sonic221116-Nov-07 11:22
membersonic221116-Nov-07 11:22 
AnswerRe: Does it work with the internet ? Pin
Sidzone20-Nov-07 9:31
memberSidzone20-Nov-07 9:31 
GeneralRe: Does it work with the internet ? Pin
Mohandas P G2-Sep-11 0:10
memberMohandas P G2-Sep-11 0:10 
GeneralMDI and Show - How can I use it in this source Pin
maithang_longthanh21-Jun-07 16:18
membermaithang_longthanh21-Jun-07 16:18 
GeneralRe: MDI and Show - How can I use it in this source Pin
Josip8418-Dec-12 2:09
memberJosip8418-Dec-12 2:09 
GeneralNice article Pin
xs2mini11-Apr-07 3:17
memberxs2mini11-Apr-07 3:17 
GeneralThank you Pin
duc_clo8-Apr-07 18:01
memberduc_clo8-Apr-07 18:01 
GeneralNice and simple - thanks! Pin
Patrick Sears31-Jan-07 9:05
memberPatrick Sears31-Jan-07 9:05 
GeneralThank you for the code Pin
Sin Jeong-hun18-Jan-07 5:51
memberSin Jeong-hun18-Jan-07 5:51 
GeneralRe: Thank you for the code Pin
Sidzone31-Jan-07 9:12
memberSidzone31-Jan-07 9:12 
GeneralPrepare your code Pin
Sceptic Mole5-Nov-06 2:57
memberSceptic Mole5-Nov-06 2:57 
GeneralRe: Prepare your code Pin
Sidzone26-Feb-07 23:36
memberSidzone26-Feb-07 23:36 
Generalclient server Pin
hduani27-Oct-06 5:45
memberhduani27-Oct-06 5:45 
GeneralRe: client server Pin
Sidzone31-Oct-06 20:09
memberSidzone31-Oct-06 20:09 
GeneralRe: client server Pin
chal_adiera31-Oct-06 20:59
memberchal_adiera31-Oct-06 20:59 
GeneralRe: client server Pin
chal_adiera31-Oct-06 21:18
memberchal_adiera31-Oct-06 21:18 
GeneralRe: client server Pin
Sidzone1-Nov-06 2:35
memberSidzone1-Nov-06 2:35 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160929.1 | Last Updated 31 Jan 2007
Article Copyright 2006 by Sidzone
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid