C# .NET - Creating a Multi-User TCP Chat Application

Asked By pravin kumar S on 25-Sep-08 04:43 AM
i am developing Creating a Multi-User TCP Chat Application useing help of MSDN but in case when i run the appliction only client form are running ...so please help me//

Similar application - Perry replied to pravin kumar S on 25-Sep-08 04:53 AM

This will be basically client-server application where multiple client will connect to the server. You will need to create the thread for each new client connection. The one Worker thread will keep track of all the clients. You will need to use C# Queue for receiving the client requests and synchronize them and use Socket for communication between client and server. I have similar application in VS.NET as below:

Imports System.Threading
Imports System.Net
Imports System.Net.Sockets

Public Delegate Sub StatusInvoker(ByVal t As String)

Public Class Form1
  Inherits System.Windows.Forms.Form

  Private mobjThread As Thread
  Private mobjListener As TcpListener
  Private mcolClients As New Hashtable()

#Region " Windows Form Designer generated code "

  Public Sub New()
    MyBase.New()

    'This call is required by the Windows Form Designer.
    InitializeComponent()

    'Add any initialization after the InitializeComponent() call

  End Sub

  'Form overrides dispose to clean up the component list.
  Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
      If Not (components Is Nothing) Then
        components.Dispose()
      End If
    End If
    MyBase.Dispose(disposing)
  End Sub
  Friend WithEvents lstStatus As System.Windows.Forms.ListBox

  'Required by the Windows Form Designer
  Private components As System.ComponentModel.Container

  'NOTE: The following procedure is required by the Windows Form Designer
  'It can be modified using the Windows Form Designer. 
  'Do not modify it using the code editor.
  <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.lstStatus = New System.Windows.Forms.ListBox
        Me.SuspendLayout()
        '
        'lstStatus
        '
        Me.lstStatus.Dock = System.Windows.Forms.DockStyle.Fill
        Me.lstStatus.Location = New System.Drawing.Point(0, 0)
        Me.lstStatus.Name = "lstStatus"
        Me.lstStatus.Size = New System.Drawing.Size(292, 264)
        Me.lstStatus.TabIndex = 0
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 273)
        Me.Controls.Add(Me.lstStatus)
        Me.Name = "Form1"
        Me.Text = "Socket Server"
        Me.ResumeLayout(False)

    End Sub

#End Region

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        mobjThread = New Thread(AddressOf DoListen)
        mobjThread.Start()
    UpdateStatus("Listener started")
  End Sub

  Private Sub DoListen()
    Try
            mobjListener = New TcpListener(IPAddress.Any, 5001)

      mobjListener.Start()
      Do
        'Dim x As New Client(mobjListener.AcceptSocket)
        Dim x As New Client(mobjListener.AcceptTcpClient)

                AddHandler x.Connected, AddressOf OnConnected
        AddHandler x.Disconnected, AddressOf OnDisconnected
        'AddHandler x.CharsReceived, AddressOf OnCharsReceived
        AddHandler x.LineReceived, AddressOf OnLineReceived
        mcolClients.Add(x.ID, x)
        Dim params() As Object = {"New connection"}
        Me.Invoke(New StatusInvoker(AddressOf Me.UpdateStatus), params)
      Loop Until False
    Catch
    End Try
  End Sub

  Private Sub OnConnected(ByVal sender As Client)
        UpdateStatus("Connected")
  End Sub

  Private Sub OnDisconnected(ByVal sender As Client)
    UpdateStatus("Disconnected")
    mcolClients.Remove(sender.ID)
  End Sub

  'Private Sub OnCharsReceived(ByVal sender As Client, ByVal Data As String)
  '  UpdateStatus("Chars:" & Data)
  'End Sub

  Private Sub OnLineReceived(ByVal sender As Client, ByVal Data As String)
    UpdateStatus("Line:" & Data)

    Dim objClient As Client
    Dim d As DictionaryEntry

    For Each d In mcolClients
      objClient = d.Value
      objClient.Send(Data & vbCrLf)
    Next
  End Sub

  Private Sub UpdateStatus(ByVal t As String)
    lstStatus.Items.Add(t)
    lstStatus.SetSelected(lstStatus.Items.Count - 1, True)
  End Sub

  Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
    mobjListener.Stop()
  End Sub
End Class

-Paresh

C# application - Perry replied to pravin kumar S on 25-Sep-08 04:54 AM

Using connection-oriented sockets

In the .NET Framework, you can create connection-oriented communications with remote hosts across a network. To create a connection-oriented socket, separate sequences of functions must be used for server programs and client programs:

Server

You have four tasks to perform before a server can transfer data with a client connection:

  1. Create a socket.
  2. Bind the socket to a local IPEndPoint.
  3. Place the socket in listen mode.
  4. Accept an incoming connection on the socket.

Creating the server

The first step to constructing a TCP server is to create an instance of the Socket object. The other three functions necessary for successful server operations are then accomplished by using the methods of Socket object. The following C# code snippet includes these steps:

IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 8000);
Socket newsock = Socket(AddressFamily.InterNetwork,
                   SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(localEndPoint);
newsock.Listen(10);
Socket client = newsock.Accept();

The Socket object created by the Accept() method can now be used to transmit data in either direction between the server and the remote client.

Client

Now that you have a working TCP server, you can create a simple TCP client program to interact with it. There are only two steps required to connect a client program to a TCP server:

  1. Create a socket.
  2. Connect the socket to the remote server address.

Creating the client

As it was for the server program, the first step for creating the client program is to create a Socket object. The Socket object is used by the socket Connect() method to connect the socket to a remote host:

IPEndPoint ipep = 
    new IPEndPoint(Ipaddress.Parse("127.0.0.1"), 8000);
Socket server = new Socket(AddressFamily.InterNetwork,
                  SocketType.Stream, ProtocolType.Tcp);
server.Connect(ipep);
refer http://www.codeproject.com/KB/IP/TCPIPChat.aspx for details.
 

sending and receiving data - Perry replied to pravin kumar S on 25-Sep-08 04:56 AM

Use the infinite while loop for sendind and receiving data like below:

while ( this.clientSocket.Connected )
{
    //Read the command's Type.
    byte [] buffer = new byte [4];
    int readBytes = this.networkStream.Read(buffer , 0 , 4);
    if ( readBytes == 0 )
      break;
    CommandType cmdType = 
         (CommandType)( BitConverter.ToInt32(buffer , 0) );
    
    //Read the command's sender ip size.
    buffer = new byte [4];
    readBytes = this.networkStream.Read(buffer , 0 , 4);
    if ( readBytes == 0 )
    break;
    int senderIPSize = BitConverter.ToInt32(buffer , 0);
    
    //Read the command's sender ip.
    buffer = new byte [senderIPSize];
    readBytes = 
        this.networkStream.Read(buffer , 0 , senderIPSize);
    if ( readBytes == 0 )
      break;
    IPAddress senderIP = IPAddress.Parse(
             System.Text.Encoding.ASCII.GetString(buffer));
    
    //Read the command's sender name size.
    buffer = new byte [4];
    readBytes = this.networkStream.Read(buffer , 0 , 4);
    if ( readBytes == 0 )
      break;
    int senderNameSize = BitConverter.ToInt32(buffer , 0);
    
    //Read the command's sender name.
    buffer = new byte [senderNameSize];
    readBytes = this.networkStream.Read(buffer, 0, senderNameSize);
    if ( readBytes == 0 )
      break;
    string senderName = 
        System.Text.Encoding.Unicode.GetString(buffer);
    
    //Read the command's target size.
    string cmdTarget = "";
    buffer = new byte [4];
    readBytes = this.networkStream.Read(buffer , 0 , 4);
    if ( readBytes == 0 )
       break;
    int ipSize = BitConverter.ToInt32(buffer , 0);
    
    //Read the command's target.
    buffer = new byte [ipSize];
    readBytes = this.networkStream.Read(buffer , 0 , ipSize);
    if ( readBytes == 0 )
      break;
    cmdTarget = System.Text.Encoding.ASCII.GetString(buffer);
    
    //Read the command's MetaData size.
    string cmdMetaData = "";
    buffer = new byte [4];
    readBytes = this.networkStream.Read(buffer , 0 , 4);
    if ( readBytes == 0 )
      break;
    int metaDataSize = BitConverter.ToInt32(buffer , 0);
    
    //Read the command's Meta data.
    buffer = new byte [metaDataSize];
    readBytes = this.networkStream.Read(buffer , 0 , metaDataSize);
    if ( readBytes == 0 )
         break;
    cmdMetaData = System.Text.Encoding.Unicode.GetString(buffer);
                  
    Command cmd = new Command(cmdType, 
                        IPAddress.Parse(cmdTarget), cmdMetaData);
    cmd.SenderIP = senderIP;
    cmd.SenderName = senderName;
    this.OnCommandReceived(new CommandEventArgs(cmd));
    }
    this.OnServerDisconnected(new ServerEventArgs(this.clientSocket));
    this.Disconnect();
}
-Paresh
Complete Chat application code in C# - Perry replied to pravin kumar S on 25-Sep-08 04:58 AM

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Threading;

namespace Wrox.WindowsGUIProgramming.Chapter9
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class ChatApplication : System.Windows.Forms.Form
    {
        internal System.Windows.Forms.ListBox listBox1;
        private System.Windows.Forms.TextBox txtMessage;
        private System.Windows.Forms.Button btSend;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
        private System.Windows.Forms.ComboBox cmdHost;
        private System.Windows.Forms.CheckBox chkSuspendClient;

        private PeerConnection p = null;

        public ChatApplication()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
            p = new PeerConnection(4048, listBox1, cmdHost);
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Disposebool disposing )
        {
            ifdisposing )
            {
                if (components != null
                {
                    components.Dispose();
                }
            }
            base.Disposedisposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.listBox1 = new System.Windows.Forms.ListBox();
            this.txtMessage = new System.Windows.Forms.TextBox();
            this.btSend = new System.Windows.Forms.Button();
            this.cmdHost = new System.Windows.Forms.ComboBox();
            this.chkSuspendClient = new System.Windows.Forms.CheckBox();
            this.SuspendLayout();
            // 
            // listBox1
            // 
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(688394);
            this.listBox1.TabIndex = 0;
            // 
            // txtMessage
            // 
            this.txtMessage.Location = new System.Drawing.Point(8408);
            this.txtMessage.Name = "txtMessage";
            this.txtMessage.Size = new System.Drawing.Size(57620);
            this.txtMessage.TabIndex = 1;
            this.txtMessage.Text = "";
            // 
            // btSend
            // 
            this.btSend.Location = new System.Drawing.Point(608408);
            this.btSend.Name = "btSend";
            this.btSend.TabIndex = 2;
            this.btSend.Text = "Send";
            this.btSend.Click += new System.EventHandler(this.btSend_Click);
            // 
            // cmdHost
            // 
            this.cmdHost.Location = new System.Drawing.Point(8432);
            this.cmdHost.Name = "cmdHost";
            this.cmdHost.Size = new System.Drawing.Size(52021);
            this.cmdHost.TabIndex = 3;
            this.cmdHost.Text = "localhost";
            // 
            // chkSuspendClient
            // 
            this.chkSuspendClient.Location = new System.Drawing.Point(544432);
            this.chkSuspendClient.Name = "chkSuspendClient";
            this.chkSuspendClient.Size = new System.Drawing.Size(15224);
            this.chkSuspendClient.TabIndex = 4;
            this.chkSuspendClient.Text = "Suspend Client";
            this.chkSuspendClient.CheckedChanged += new System.EventHandler(this.chkSuspendClient_CheckedChanged);
            // 
            // ChatApplication
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(513);
            this.ClientSize = new System.Drawing.Size(688462);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.chkSuspendClient,
                                                                          this.cmdHost,
                                                                          this.btSend,
                                                                          this.txtMessage,
                                                                          this.listBox1});
            this.MaximizeBox = false;
            this.Name = "ChatApplication";
            this.Text = "Chat!";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new ChatApplication());
        }

        private void btSend_Click(object sender, System.EventArgs e)
        {
            p.Write(txtMessage.Text);
        }

        private void chkSuspendClient_CheckedChanged(object sender, System.EventArgs e)
        {
            if(chkSuspendClient.Checked==true)
            {
                p.Enabled = true;
            }
            else
            {
                p.Enabled = false;
            }
        }
    }


    public class PeerConnection
    {
        private System.Net.Sockets.TcpListener peerListener = null;
        private System.Net.Sockets.TcpClient peerClient = null;
        private System.Net.Sockets.NetworkStream netStream = null;
        private Thread t1 = null;
        private IntPtr formHandle;
        private int port = 0;
        private bool clientEnabled = true;
        private ListBox lb;
        private ComboBox cmb;

        public PeerConnection(int port, ListBox formHandle, ComboBox cmdHost)
        {
            this.port = port;
            this.lb = formHandle;
            this.cmb = cmdHost;
            t1 = new Thread(new ThreadStart(CreateListener));
            t1.Name = "Listener Thread";
            t1.Priority = ThreadPriority.AboveNormal;
            t1.Start();
        }

        delegate void CallbackListbox(string message);

        void SetListboxString(string item)
        {
            lb.Items.Add(item);
        }

        private void CreateListener()
        {
            Socket tc = null;

            peerListener = new TcpListener(port);
            peerListener.Start();

            CallbackListbox clb = new CallbackListbox(SetListboxString);
            while(true)
            {
                tc = peerListener.AcceptSocket();
                byte[] byMessage = new byte[256];
                Thread.Sleep(500);
                int iLength = tc.Receive(byMessage, 0, byMessage.Length, SocketFlags.None)
                if(iLength>0)
                {
                    string message = System.Text.Encoding.Default.GetString(byMessage);
                    try
                    {
                        if(lb.InvokeRequiredlb.Invoke(clb, new object[]{message});
                    }
                    catch(Exception e)
                    {
                        message = e.Message;
                    }
                    finally
                    {
                        System.Diagnostics.Debug.WriteLine(message);
                    }
                }
            }
        }

        private void CreateClient(object message)
        {
            peerClient = new TcpClient();
            peerClient.Connect(cmb.SelectedText, port);

            netStream = peerClient.GetStream();

            StreamWriter sw = new StreamWriter(netStream);
            sw.Write((string)message);
            sw.Flush();

            peerClient.Close();
        }

        internal void Write(string message)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(CreateClient), message);
        }

        internal bool Enabled
        {
            set
            {
                if(t1.ThreadState==ThreadState.Suspended&&value==true)
                {
                    t1.Resume();
                }
                else if(t1.ThreadState!=ThreadState.Suspended&&value==false)
                {
                    t1.Suspend();
                }
                clientEnabled = value;
            }
            get
            {
                return clientEnabled;
            }   
        }
    }
}

refer http://www.java2s.com/Code/CSharp/Network/ChatApplication.htm for details.

-PAresh


hi - pravin kumar S replied to Perry on 25-Sep-08 05:42 AM

thank for reply but when i run the application only client form are running so i am asking all the code is same

hi - pravin kumar S replied to Perry on 25-Sep-08 05:43 AM

thank for reply but when i run the application only client form are running so i am asking all the code is same

serves side code - Perry replied to pravin kumar S on 25-Sep-08 06:05 AM

Hey Buddy, server side code will be mirror image of client side code. You just need to change the reading-writing sequences to synchronize it and need to create the threads for each new connection.

-Paresh