Click here to Skip to main content
Click here to Skip to main content

A Simple Multi-Threaded Server Client Instant Messenger Application

By , 4 Jun 2006
 
Sample Image - maximum width is 600 pixels

The Library Project

I created a ChatLibrary that will contain the valid commands and a Message that will contain the parsing.

public enum Command
{
   Login = 0,
   PersonalMessage = 1,    
   ClientList = 2,        
   Conference = 3,
   Logout = 4        
};

public class Message
{
string strSender;
string strReceiver;
Command cmdMessageCommand;
string strMessageDetail;
public Message ()
{
}
public Message (byte [] rawMessage)
{
  string strRawStringMessage = System.Text.Encoding.ASCII.GetString (rawMessage);   
  string [] strRawStringMessageArray = strRawStringMessage.Split(new char []{'|'});
  this.strSender = strRawStringMessageArray[1];
  this.strReceiver = strRawStringMessageArray[2];
  this.cmdMessageCommand = (Command) Convert.ToInt32(strRawStringMessageArray[3]);
  this.MessageDetail = strRawStringMessageArray[4];
}
...

public byte [] GetRawMessage ()
{
   System.Text.StringBuilder sbMessage = new System.Text.StringBuilder ("John");
   sbMessage.Append("|");
   sbMessage.Append(strSender);
   sbMessage.Append("|");
   sbMessage.Append(strReceiver);
   sbMessage.Append("|");
   sbMessage.Append((int)cmdMessageCommand);
   sbMessage.Append("|");
   sbMessage.Append(strMessageDetail);
   sbMessage.Append("|");
   return System.Text.Encoding.ASCII.GetBytes(sbMessage.ToString());
}
...

The Server Project

I created a SocketServer that calls the TCPListener.Start() method:

IPEndPoint endPoint = new IPEndPoint (ipaAddress, iPort);
listener = new TcpListener (endPoint);
listener.Start();

Upon calling Listen, a new thread will be created that will listen for incoming clients:

thrListenForClients = new Thread(new ThreadStart(ListenForClients));
thrListenForClients.Start();

The ListenForClients method will wait for connections and will assign the incoming socket to a new Client instance:

Client acceptClient = new Client();
acceptClient.Socket = listener.AcceptTcpClient();
listenForMessageDelegate = new ListenForMessageDelegate (ListenForMessages);
listenForMessageDelegate.BeginInvoke
    (acceptClient, new AsyncCallback(ListenForMessagesCallback), "Completed");

The Client, by the way is a class that contains a TCPClient, so we can keep track of our connections:

public class Client {
   string strName;
   TcpClient tcpClient;
   public Client()
   {
   }
   public string Name 
   {
    get{return strName;}
    set{ this.strName = value;}            
   }
   public TcpClient Socket
   {
    get{return tcpClient;}
    set{ this.tcpClient = value;}
   }
   public void SendMessage (Message sendMessage)
   {
    NetworkStream stream = tcpClient.GetStream();
    stream.Write(sendMessage.GetRawMessage() , 0, sendMessage.GetRawMessage().Length);            
   }
}

Our server is now ready to listen for incoming messages. To do this, we pass the client socket that we received, then make a loop. We use a NetworkStream to read the message:

NetworkStream stream = client.Socket.GetStream();
byte [] bytAcceptMessage = new byte [1024];
stream.Read(bytAcceptMessage, 0, bytAcceptMessage.Length);
Message message = new ChatLibrary.Message(bytAcceptMessage);

Once we receive the message, we can do anything that we want:

txtStatus.Text += "\r\n" + strDisplayMessageType + 
    strWriteText.TrimStart(new char[]{'\r','\n'});

My SocketServer makes use of a few events that make coding a little easier:

public event ClientConnectedEventHandler ClientConnected;
public event ClientDisconnectingEventHandler ClientDisconnecting;
public event MessageReceivedEventHandler MessageReceived;

In my ServerForm code, what I did was I kept a copy of each connected Client in a ClientCollection that inherits from System.Collections.CollectionBase. With this, I can iterate through the Clients.

The Client Project

The Client does basically the same thing. I created a ClientSocket that will create a TCPListener and call Connect():

IPEndPoint serverEndpoint = new IPEndPoint (ipaAddress , iPort);
tcpClient = new TcpClient ();
tcpClient.Connect(serverEndpoint);
thrListenForMessages = new Thread (new ThreadStart(ListenForMessages));
thrListenForMessages.Start();

What ListenForMessages will do is loop with NetworkStream.Read():

stream = tcpClient.GetStream();
byte [] bytRawMessage = new byte [1024];
stream.Read(bytRawMessage, 0, bytRawMessage.Length);
ChatMessage receivedMessage = new ChatLibrary.Message (bytRawMessage);

Then we do the same process, create a Message using the received bytes.

Again, my goal is to create a YM/MSN - looking Instant Messenger, so I made two UI forms. The MessengerForm and the ClientWindow. The MessengerForm is the class that instantiates the ClientSocket and receives the messages. Upon receiving a message, it calls the MessengerWindow that should display the text.

Note that I didn't do a regular instantiation. I called Invoke to be able to make my controls thread safe:

this.Invoke(createNewClientDelegate, new object []{receivedMessage});

History

  • 4th June 2006: Initial version

License

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

About the Author

John Conrad
Web Developer
Philippines Philippines
John lives in the Philippines with his family, working as a programmer. He used to program VB6 but is now... ummm... trying to learn C# .Net.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalthis code can not send bytes>1024memberdaodetianzun19-Sep-08 4:09 
GeneralGreat but there are some errors to modifymemberSugathe0427-Aug-08 18:43 
GeneralHelp Please: If I kick a client, or client click disconnect, the server raises a error of "Server has stopped working"memberJameYoon2-Jul-08 17:35 
GeneralPlease Help :) If I stop the Server(even if there is no client connected), it arises an error. [modified]memberJameYoon1-Jul-08 18:18 
QuestionNot sure how to use!!!memberLecram21-Jun-08 20:34 
GeneralCross-thread operation not valid: Control 'txtStatus' accessed from a thread other than the thread it was created on.memberShawn12814-Jun-08 22:42 
AnswerRe: Cross-thread operation not valid: Control 'txtStatus' accessed from a thread other than the thread it was created on.memberJason Barry25-Jun-08 2:57 
GeneralRe: Cross-thread operation not valid: Control 'txtStatus' accessed from a thread other than the thread it was created on.memberMember 87892936-Apr-12 10:16 
QuestionClient IP-Address problemmemberHusti5-Apr-08 9:03 
GeneralSystem.ObjectDisposedException after disconnectmemberGaara [BTK]15-Aug-07 14:22 
GeneralRe: System.ObjectDisposedException after disconnectmemberAntbu1325-Oct-07 20:41 
GeneralRe: System.ObjectDisposedException after disconnectmemberEagleTwo20-May-09 10:43 
Generalproblem in running this application [modified]membervrani12-Jul-07 19:38 
GeneralMulti-threading error fixmemberstormist10-Jun-07 13:43 
Generaltextboxmemberdark_magician_65-May-07 4:50 
Questionnot working on lan plz help mememberMember #37941123-Mar-07 0:26 
Questionit is working in LAN but what do i need to do for WAN ?memberevalenzuela2-Feb-07 11:57 
GeneralErrormemberChristian Siebmanns7-Oct-06 5:04 
GeneralRe: Errormemberbubbler_below9-Oct-06 17:09 
GeneralRe: Errormemberbubbler_below10-Oct-06 22:25 
GeneralRe: ErrormemberChristian Siebmanns21-Oct-06 5:24 
AnswerRe: Errormemberduffer_0113-Apr-07 10:30 
AnswerRe: Errormember@Jim13-Aug-07 10:06 
GeneralRe: Errormembershnewaz20-Apr-08 6:55 
GeneralRe: ErrormembermarcoTDI13-May-08 21:47 
Generalhimemberibless17-Aug-06 12:32 
GeneralRe: himemberChristian Siebmanns21-Oct-06 5:07 
Generalvery nice workmemberDarchangel3-Aug-06 4:00 
GeneralRe: very nice workmembershnewaz20-Apr-08 6:57 
GeneralRichtext FormattingmemberYadav Pramod26-Jul-06 21:54 
GeneralRe: Richtext Formattingmembermassivegas29-Jul-06 21:12 
GeneralGood applicationmemberdeepak_int18-Jun-06 19:28 
GeneralRe: Good applicationmembermassivegas19-Jun-06 20:25 
GeneralIt worksmemberrduan12-Jun-06 9:04 
GeneralYou got my 5 for...memberJun Du5-Jun-06 4:18 
Generalhimembernina0003-Mar-08 6:04 

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 5 Jun 2006
Article Copyright 2006 by John Conrad
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid