C chat program server and client complete instance code

  • 2020-06-23 01:48:05
  • OfStack

This article describes the C# based implementation of the multi-user chat program server and client complete code. This example omitted the structure definition part, the server side mainly is the logic processing part of the code, therefore needs to perfect 1 form button and so on when using.

Take a look at the server code as follows:


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace  Multiplayer chat program Server end 
{
 /// <summary>
 ///  The main entry point to the application. 
 /// </summary>
 [STAThread]
 static void Main()
 {
  Application.Run(new Form1());
 }
 //  Start service button 
 private void button2_Click(object sender, System.EventArgs e)
 {
  try
  {
  //  Port must be filled in 
  if(txtPort.Text == "")
  {
   MessageBox.Show(" Please fill in the service port number first !", " prompt ");
   return;
  }
  Int32 port = Int32.Parse(txtPort.Text); //  Get the port number 
  //  Create listening Socket
  mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);
  //  will  Socket  Bind to a local endpoint 
  mainSocket.Bind(localEP);
  //  Start listening. The maximum number of connections is  5
  mainSocket.Listen(5);
  //  start 1 An asynchronous operation accepts a client's connection request 
  mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
  //  The start service button is not available and the stop service button is available 
  UpdateControls(true);
  }
  catch(SocketException se)
  {
  MessageBox.Show(se.Message, " prompt ");
  }
 }
 //  Update the status of the Start Service button and Stop Service button: is it available? 
 //  Note: The states of the two buttons are mutually exclusive 
 private void UpdateControls(bool onServe)
 {
  button2.Enabled = !onServe;
  button3.Enabled = onServe;
  if(onServe)
  {
  status.Text = " Started service ";
  }
  else
  {
  status.Text = " Unstarted service ";
  }
 }
 //  The callback function will be called when the client connects 
 public void OnClientConnect(IAsyncResult asyn)
 {
  try
  {
  //  call EndAccept complete BeginAccept Asynchronous call, return 1 A new one Socket Handle communication with customers 
  Socket workerSocket = mainSocket.EndAccept(asyn);
  //  Increase the number of customers 
  Interlocked.Increment(ref clientNum);
  //  will  workerSocket Socket To join the  ArrayList  In the 
  workerSocketList.Add(workerSocket);
  //  Send a welcome message to the customer who is connected to the server 
  string msg = " Welcome customer  " + clientNum + "  Login server \n";
  SendWelcomeToClient(msg, clientNum);
  //  The number of online customers has changed and the customer list must be updated 
  UpdateClientListControl();
  //  The customer on the connection receives the data 
  WaitForData(workerSocket, clientNum);
  //  The main  Socket  Return and continue to wait for other connection requests 
  mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
  }
  catch(ObjectDisposedException)
  {
  System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket Has been closed !\n");
  }
  catch(SocketException se)
  {
  MessageBox.Show(se.Message, " prompt ");
  }
 }
 //  Send a welcome message to the customer 
 void SendWelcomeToClient(string msg, int clientNumber)
 {
  //  with UTF8 Format to string Transform information into byte An array 
  byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
  //  Get the customer clientNumber The corresponding Socket
  Socket workerSocket = (Socket)workerSocketList[clientNumber - 1];
  //  Send the data to the customer 
  workerSocket.Send(byData);
 }
 //  This class saves the current socket , its customer number and the data sent to the server 
 public class SocketPacket
 {
  public System.Net.Sockets.Socket currentSocket; //  The current Socket
  public int clientNumber; //  Customer number 
  public byte[] dataBuffer = new byte[1024]; //  Data sent to the server 
  //  The constructor 
  public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber)
  {
  currentSocket = socket;
  this.clientNumber = clientNumber;
  }
 }
 //  Start waiting for the customer to send data 
 public void WaitForData(System.Net.Sockets.Socket socket, int clientNumber)
 {
  try
  {
  if(pfnWorkerCallBack == null)
  {
   //  The callback function is called when the client on the connection has a write operation 
   pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
  }
  SocketPacket socketPacket = new SocketPacket(socket, clientNumber);
  socket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
            SocketFlags.None, pfnWorkerCallBack, socketPacket);
  }
  catch(SocketException se)
  {
  MessageBox.Show (se.Message, " prompt ");
  }
 }
 //  When a customer writes data, the following method is called 
 public void OnDataReceived(IAsyncResult asyn)
 {
  SocketPacket socketData = (SocketPacket)asyn.AsyncState ;
  try
  {
  // EndReceive complete BeginReceive An asynchronous call that returns the number of bytes the customer wrote into the stream 
  int iRx = socketData.currentSocket.EndReceive(asyn);
  //  add  1  Because the string starts with  '\0'  As the end flag 
  char[] chars = new char[iRx + 1];
  //  Conduct information from customers UTF8 Decode, store chars Character array 
  System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
  int charLen = decoder.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
  System.String szData = new System.String(chars);
  string msg = " The customer  " + socketData.clientNumber + "  Send the information :" + szData;
  //  Add the data sent by the customer to the information list 
  AppendToRichEditControl(msg);
  //  Waiting for data 
  WaitForData(socketData.currentSocket, socketData.clientNumber);
  }
  catch (ObjectDisposedException )
  {
  System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket Has been closed !\n");
  }
  catch(SocketException se)
  {
  if(se.ErrorCode == 10054)
  {
   //  Writes the client disconnect information to the information list 
   string msg = " The customer  " + socketData.clientNumber + "  The connection has been disconnected !" + "\n";
   AppendToRichEditControl(msg);
   //  Remove the closed ones socket
   workerSocketList[socketData.clientNumber - 1] = null;
   //  Update customer list 
   UpdateClientListControl();
  }
  else
  {
   MessageBox.Show (se.Message, " prompt ");
  }
  }
 }
 //  Update the list of information that can be called by the main thread or another worker thread 
 private void AppendToRichEditControl(string msg)
 {
  //  Test to see which thread called the method 
  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 which will
  // be called when the Main thread is free
  // Do UI update on UI thread
  object[] pList = {msg};
  txtRecvMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList);
  }
  else
  {
  //  Create the main thread of the control to update the list of information directly 
  OnUpdateRichEdit(msg);
  }
 }
 //  Add information to  txtRecvMsg  In the 
 private void OnUpdateRichEdit(string msg)
 {
 // txtRecvMsg.AppendText(msg);
  txtRecvMsg.Text = txtRecvMsg.Text + msg;
 }
 //  Update customer list 
 private void UpdateClientListControl()
 {
  if (InvokeRequired) // Is this called from a thread other than the one created
  // the control
  {
  clientList.BeginInvoke(new UpdateClientListCallback(UpdateClientList), null);
  }
  else
  {
  //  Create the main thread of the control to update the list of information directly 
  UpdateClientList();
  }
 }
 //  Update customer list 
 void UpdateClientList()
 {
  clientList.Items.Clear(); //  Clear customer list 
  for(int i = 0; i < workerSocketList.Count; i++)
  {
  //  add 1 That's because the array starts from the subscript 0 And our customer number is from 1 start 
  string clientKey = Convert.ToString(i + 1);
  Socket workerSocket = (Socket)workerSocketList[i];
  if(workerSocket != null)
  {
   //  Add the customers connected to the server to the customer list 
   if(workerSocket.Connected)
   {
   clientList.Items.Add(clientKey);
   }
  }
  }
 }
 //  Stop button 
 private void button3_Click(object sender, System.EventArgs e)
 {
  CloseSockets();
  UpdateControls(false);
  //  Update customer list 
  UpdateClientListControl();
 }
 //  Send message button 
 private void button1_Click(object sender, System.EventArgs e)
 {
  //  If the online customer list is not empty, messages are allowed to be sent 
  if (clientList.Items.Count != 0 )
  {
  try
  {
   string msg = txtSendMsg.Text;
   msg = " Server information : " + msg + "\n";
   byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
   Socket workerSocket = null;
   for(int i = 0; i < workerSocketList.Count; i++)
   {
   workerSocket = (Socket)workerSocketList[i];
   if(workerSocket!= null)
   {
    //  To all customers connected to the server 
    if(workerSocket.Connected)
    {
    workerSocket.Send(byData);
    }
   }
   }
  }
  catch(SocketException se)
  {
   MessageBox.Show(se.Message, " prompt ");
  }
  }
  else
  {
  MessageBox.Show(" No online customers , Can't send a message !", " prompt ");
  }
 }
 //  Clear information button 
 private void button4_Click(object sender, System.EventArgs e)
 {
  txtRecvMsg.Clear(); //  Empty messages from customers 
 }
 //  Close form button 
 private void button5_Click(object sender, System.EventArgs e)
 {
  CloseSockets();
  Close();
 }
 //  Shut down Socket
 void CloseSockets()
 {
  //  Shut down the main Socket
  if(mainSocket != null)
  {
  mainSocket.Close();
  }
  Socket workerSocket = null;
  //  Shut down the customer  Socket  An array of 
  for(int i = 0; i < workerSocketList.Count; i++)
  {
  workerSocket = (Socket)workerSocketList[i];
  if(workerSocket != null)
  {
   workerSocket.Close();
   workerSocket = null;
  }
  }
 }
 private void Form1_Load(object sender, System.EventArgs e)
 {
  try
  {
  //  Obtain the local IP address 
  txtIP.Text = Dns.Resolve(Dns.GetHostName()).AddressList[0].ToString();
  //  On startup, the Start service button is available and the Stop service button is not 
  UpdateControls(false);
  }
  catch(Exception exc)
  {
  MessageBox.Show(exc.Message, " prompt ");
  }
 }
 }
}

The client mainly realizes the operation interface of receiving messages returned from the server and sending messages, creates Socket instance, gets the IP address of the server, updates the control, connects and disconnects, etc. The specific code is as follows:


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
namespace  Multiplayer chat program Client end 
{
 public class Form1 : System.Windows.Forms.Form
 {
 private System.Windows.Forms.Label label1;
 private System.Windows.Forms.TextBox txtIP;
 private System.Windows.Forms.Label label2;
 private System.Windows.Forms.Label label3;
 private System.Windows.Forms.RichTextBox txtSendMsg;
 private System.Windows.Forms.Label label4;
 private System.Windows.Forms.Button button1;
 private System.Windows.Forms.Button button2;
 private System.Windows.Forms.Button button3;
 private System.Windows.Forms.Button button4;
 private System.Windows.Forms.RichTextBox txtRecvMsg;
 private System.Windows.Forms.TextBox txtPort;
 private System.Windows.Forms.Button button5;
 private System.ComponentModel.Container components = null;
 byte[] m_dataBuffer = new byte[10];
 IAsyncResult result;
 public AsyncCallback pfnCallBack ;
 private System.Windows.Forms.Label status;
 private System.Windows.Forms.Label label5;
 public Socket clientSocket;
 public Form1()
 {
  InitializeComponent();
 }
 private void InitializeComponent()
 {
  this.label1 = new System.Windows.Forms.Label();
  this.txtIP = new System.Windows.Forms.TextBox();
  this.label2 = new System.Windows.Forms.Label();
  this.txtPort = new System.Windows.Forms.TextBox();
  this.label3 = new System.Windows.Forms.Label();
  this.txtSendMsg = new System.Windows.Forms.RichTextBox();
  this.label4 = new System.Windows.Forms.Label();
  this.status = new System.Windows.Forms.Label();
  this.txtRecvMsg = new System.Windows.Forms.RichTextBox();
  this.button1 = new System.Windows.Forms.Button();
  this.button2 = new System.Windows.Forms.Button();
  this.button3 = new System.Windows.Forms.Button();
  this.button4 = new System.Windows.Forms.Button();
  this.label5 = new System.Windows.Forms.Label();
  this.button5 = new System.Windows.Forms.Button();
  this.SuspendLayout();
  // label1
  this.label1.AutoSize = true;
  this.label1.Location = new System.Drawing.Point(16, 24);
  this.label1.Name = "label1";
  this.label1.Size = new System.Drawing.Size(60, 17);
  this.label1.TabIndex = 0;
  this.label1.Text = " The server IP:";
  // txtIP
  this.txtIP.Location = new System.Drawing.Point(80, 24);
  this.txtIP.Name = "txtIP";
  this.txtIP.Size = new System.Drawing.Size(160, 21);
  this.txtIP.TabIndex = 1;
  this.txtIP.Text = "";
  // label2
  this.label2.AutoSize = true;
  this.label2.Location = new System.Drawing.Point(16, 56);
  this.label2.Name = "label2";
  this.label2.Size = new System.Drawing.Size(35, 17);
  this.label2.TabIndex = 2;
  this.label2.Text = " port :";
  // txtPort
  this.txtPort.Location = new System.Drawing.Point(80, 56);
  this.txtPort.Name = "txtPort";
  this.txtPort.Size = new System.Drawing.Size(40, 21);
  this.txtPort.TabIndex = 3;
  this.txtPort.Text = "";
  // label3
  this.label3.AutoSize = true;
  this.label3.Location = new System.Drawing.Point(16, 96);
  this.label3.Name = "label3";
  this.label3.Size = new System.Drawing.Size(110, 17);
  this.label3.TabIndex = 4;
  this.label3.Text = " Send a message to the server :";
  // txtSendMsg
  this.txtSendMsg.Location = new System.Drawing.Point(16, 120);
  this.txtSendMsg.Name = "txtSendMsg";
  this.txtSendMsg.Size = new System.Drawing.Size(224, 88);
  this.txtSendMsg.TabIndex = 5;
  this.txtSendMsg.Text = "";
  // label4
  this.label4.AutoSize = true;
  this.label4.Location = new System.Drawing.Point(16, 248);
  this.label4.Name = "label4";
  this.label4.Size = new System.Drawing.Size(60, 17);
  this.label4.TabIndex = 6;
  this.label4.Text = " Connection status :";
  // status
  this.status.Location = new System.Drawing.Point(80, 248);
  this.status.Name = "status";
  this.status.Size = new System.Drawing.Size(192, 23);
  this.status.TabIndex = 7;
  // txtRecvMsg
  this.txtRecvMsg.Location = new System.Drawing.Point(264, 80);
  this.txtRecvMsg.Name = "txtRecvMsg";
  this.txtRecvMsg.ReadOnly = true;
  this.txtRecvMsg.Size = new System.Drawing.Size(224, 144);
  this.txtRecvMsg.TabIndex = 8;
  this.txtRecvMsg.Text = "";
  // button1
  this.button1.Location = new System.Drawing.Point(280, 16);
  this.button1.Name = "button1";
  this.button1.Size = new System.Drawing.Size(88, 32);
  this.button1.TabIndex = 9;
  this.button1.Text = " The connection ";
  this.button1.Click += new System.EventHandler(this.button1_Click);
  // button2
  this.button2.Location = new System.Drawing.Point(384, 16);
  this.button2.Name = "button2";
  this.button2.Size = new System.Drawing.Size(88, 32);
  this.button2.TabIndex = 10;
  this.button2.Text = " Disconnect the ";
  this.button2.Click += new System.EventHandler(this.button2_Click);
  // button3
  this.button3.Location = new System.Drawing.Point(280, 232);
  this.button3.Name = "button3";
  this.button3.Size = new System.Drawing.Size(88, 32);
  this.button3.TabIndex = 11;
  this.button3.Text = " Clear information ";
  this.button3.Click += new System.EventHandler(this.button3_Click);
  // button4
  this.button4.Location = new System.Drawing.Point(384, 232);
  this.button4.Name = "button4";
  this.button4.Size = new System.Drawing.Size(88, 32);
  this.button4.TabIndex = 12;
  this.button4.Text = " Shut down ";
  this.button4.Click += new System.EventHandler(this.button4_Click);
  // label5
  this.label5.AutoSize = true;
  this.label5.Location = new System.Drawing.Point(264, 64);
  this.label5.Name = "label5";
  this.label5.Size = new System.Drawing.Size(134, 17);
  this.label5.TabIndex = 13;
  this.label5.Text = " Receive the message from the server :";
  // button5
  this.button5.Location = new System.Drawing.Point(16, 208);
  this.button5.Name = "button5";
  this.button5.Size = new System.Drawing.Size(224, 32);
  this.button5.TabIndex = 14;
  this.button5.Text = " Send a message ";
  this.button5.Click += new System.EventHandler(this.button5_Click);
  // Form1
  this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
  this.ClientSize = new System.Drawing.Size(512, 277);
  this.Controls.Add(this.button5);
  this.Controls.Add(this.label5);
  this.Controls.Add(this.button4);
  this.Controls.Add(this.button3);
  this.Controls.Add(this.button2);
  this.Controls.Add(this.button1);
  this.Controls.Add(this.txtRecvMsg);
  this.Controls.Add(this.status);
  this.Controls.Add(this.label4);
  this.Controls.Add(this.txtSendMsg);
  this.Controls.Add(this.label3);
  this.Controls.Add(this.txtPort);
  this.Controls.Add(this.label2);
  this.Controls.Add(this.txtIP);
  this.Controls.Add(this.label1);
  this.Name = "Form1";
  this.Text = " Multiplayer chat program Client end ";
  this.Load += new System.EventHandler(this.Form1_Load);
  this.ResumeLayout(false);
 }
 #endregion
 [STAThread]
 static void Main()
 {
  Application.Run(new Form1());
 }
 //  Connect button 
 private void button1_Click(object sender, System.EventArgs e)
 {
  // IP The address and port number cannot be empty 
  if(txtIP.Text == "" || txtPort.Text == "")
  {
  MessageBox.Show(" Please fill in the server completely first IP Address and port number !", " prompt ");
  return;
  }
  try
  {
  //  create Socket The instance 
  clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  //  Get the server's IP address 
  IPAddress ipAddress = IPAddress.Parse(txtIP.Text);
  Int32 port = Int32.Parse(txtPort.Text);
  //  Create a remote endpoint 
  IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
  //  Connect to a remote server 
  clientSocket.Connect(remoteEP);
  if(clientSocket.Connected)
  {
   UpdateControls(true);
   WaitForData(); //  Asynchronous wait data 
  }
  }
  catch(SocketException se)
  {
  MessageBox.Show (se.Message, " prompt ");
  UpdateControls(false);
  }
 }
 //  Waiting for data 
 public void WaitForData()
 {
  try
  {
  if(pfnCallBack == null)
  {
   //  The callback function is called when the client on the connection has a write operation 
   pfnCallBack = new AsyncCallback(OnDataReceived);
  }
  SocketPacket socketPacket = new SocketPacket();
  socketPacket.thisSocket = clientSocket;
  result = clientSocket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
   SocketFlags.None, pfnCallBack, socketPacket);
  }
  catch(SocketException se)
  {
  MessageBox.Show(se.Message, " prompt ");
  }
 }
 //  This class to save Socket And the data sent to the server 
 public class SocketPacket
 {
  public System.Net.Sockets.Socket thisSocket;
  public byte[] dataBuffer = new byte[1024]; //  Data sent to the server 
 }
 //  Receive data 
 public void OnDataReceived(IAsyncResult asyn)
 {
  try
  {
  SocketPacket theSockId = (SocketPacket)asyn.AsyncState ;
  // EndReceive complete BeginReceive An asynchronous call that returns the number of bytes the server wrote to the stream 
  int iRx = theSockId.thisSocket.EndReceive(asyn);
  //  add  1  Because the string starts with  '\0'  As the end flag 
  char[] chars = new char[iRx + 1];
  //  with UTF8 Format to string Transform information into byte An array 
  System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
  int charLen = decoder.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
  System.String szData = new System.String(chars);
  //  Displays the received information in the information list 
  txtRecvMsg.Text = txtRecvMsg.Text + szData;
  //  Waiting for data 
  WaitForData();
  }
  catch (ObjectDisposedException)
  {
  System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket Has been closed !\n");
  }
  catch(SocketException se)
  {
  if(se.ErrorCode == 10054)
  {
   string msg = " The server " + " Stop the service !" + "\n";
   txtRecvMsg.Text = txtRecvMsg.Text + msg;
   clientSocket.Close();
   clientSocket = null;
   UpdateControls(false);
  }
  else
  {
   MessageBox.Show(se.Message, " prompt ");
  }
  }
 }
 //  Update the control. The states of the connect and disconnect (send messages) buttons are mutually exclusive 
 private void UpdateControls(bool connected)
 {
  button1.Enabled = !connected;
  button2.Enabled = connected;
  button5.Enabled = connected;
  if(connected)
  {
  status.Text = " The connected ";
  }
  else
  {
  status.Text = " There is no connection ";
  }
 }
 //  Disconnect button 
 private void button2_Click(object sender, System.EventArgs e)
 {
  //  Shut down Socket
  if(clientSocket != null)
  {
  clientSocket.Close();
  clientSocket = null;
  UpdateControls(false);
  }
 }
 //  Send message button 
 private void button5_Click(object sender, System.EventArgs e)
 {
  try
  {
  //  If the client is connected to the server, it is allowed to send the information 
  if(clientSocket.Connected)
  {
   string msg = txtSendMsg.Text + "\n";
   //  with UTF8 Format to string Transform information into byte An array 
   byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
   if(clientSocket != null)
   {
   //  To send data 
   clientSocket.Send(byData);
   }
  }
  }
  catch(Exception se)
  {
  MessageBox.Show(se.Message, " prompt ");
  }
 }
 //  Delete button 
 private void button3_Click(object sender, System.EventArgs e)
 {
  txtRecvMsg.Clear(); //  Clear the information list 
 }
 //  Close button 
 private void button4_Click(object sender, System.EventArgs e)
 {
  //  Shut down Socket
  if(clientSocket != null)
  {
  clientSocket.Close();
  clientSocket = null;
  }
  Close(); //  Closed form 
 }
 private void Form1_Load(object sender, System.EventArgs e)
 {
  UpdateControls(false); //  When initialized, only the connection button is available 
 }
 }
}

Related articles: