服务器+客户端的聊天程序

在当今这样一个网络时代,很多技术都以网络为中心在诞生。本文介绍了服务器端+客户端的聊天系统,希望对大
首页 新闻资讯 行业资讯 服务器+客户端的聊天程序

最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位,所以不会SOCKET是不行的。

首先,本文主要是针对那些刚接触SOCKET编程的朋友,如果是高手,就可以不看此文啦

在开始之前,我们需要预习一些基础知识:

什么是SOCKET套接字?

SOCKET通常有那几种数据格式?

线程的概念?

(以上基本知识我就不讲了,网上这方面资料很多的,大家找资料看下吧)

我要介绍的是一个服务器端+客户端的聊天系统,程序比较简单,我先把程序运行的界面给大家看下:

上面是服务器端运行界面;下面把客户端界面贴给大家看下:

客户端界面 

功能比较简单,服务器的端口号可以在“系统菜单”里面的参数配置进行修改的。

看了上面的图,下面我们就给大家把代码贴出来:(因为程序比较简单,所以本人就没有去分层啦)

服务器端代码:

复制

 using System;   using System.Collections.Generic;   using System.ComponentModel;   using System.Data;   using System.Drawing;   using System.Text;   using System.Windows.Forms;      using System.Net;   using System.Net.Sockets;   using System.Threading;   using System.Xml;      namespace Server   {       public partial class ServerMain : Form       {           public ServerMain()           {               InitializeComponent();           }              private void ServerMain_Load(object sender, EventArgs e)           {               this.CmdStar.Enabled = true;               this.CmdStop.Enabled = false;           }              private void 配置参数ToolStripMenuItem_Click(object sender, EventArgs e)           {               Set TSet = new Set();               TSet.ShowDialog();           }            private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)           {               About TAbout = new About();               TAbout.Show();           }           /// < summary>           /// 获得XML文件中的端口号           /// < /summary>           /// < returns>< /returns>           private int GetPort()           {               try              {                   XmlDocument TDoc = new XmlDocument();                   TDoc.Load("Settings.xml");                   string TPort = TDoc.GetElementsByTagName("ServerPort")[0].InnerXml;                   return Convert.ToInt32(TPort);                  }               catch { return 6600; }//默认是6600           }              //声明将要用到的类           private IPEndPoint ServerInfo;//存放服务器的IP和端口信息           private Socket ServerSocket;//服务端运行的SOCKET           private Thread ServerThread;//服务端运行的线程           private Socket[] ClientSocket;//为客户端建立的SOCKET连接           private int ClientNumb;//存放客户端数量           private byte[] MsgBuffer;//存放消息数据              private void CmdStar_Click(object sender, EventArgs e)           {               ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);               ServerInfo=new IPEndPoint(IPAddress.Any,this.GetPort());               ServerSocket.Bind(ServerInfo);//将SOCKET接口和IP端口绑定               ServerSocket.Listen(10);//开始监听,并且挂起数为10                  ClientSocket = new Socket[65535];//为客户端提供连接个数               MsgBuffer = new byte[65535];//消息数据大小               ClientNumb = 0;//数量从0开始统计                  ServerThread = new Thread(RecieveAccept);//将接受客户端连接的方法委托给线程               ServerThread.Start();//线程开始运行                  CheckForIllegalCrossThreadCalls = false;//不捕获对错误线程的调用                  this.CmdStar.Enabled = false;               this.CmdStop.Enabled = true;               this.StateMsg.Text = "服务正在运行"+"  运行端口:"+this.GetPort().ToString();               this.ClientList.Items.Add("服务于 " + DateTime.Now.ToString() + " 开始运行.");           }                      //接受客户端连接的方法           private void RecieveAccept()           {               while (true)               {                   ClientSocket[ClientNumb] = ServerSocket.Accept();                   ClientSocket[ClientNumb].BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(RecieveCallBack),ClientSocket[ClientNumb]);                   this.ClientList.Items.Add(ClientSocket[ClientNumb].RemoteEndPoint.ToString()+" 成功连接服务器.");                   ClientNumb++;               }           }              //回发数据给客户端          private void RecieveCallBack(IAsyncResult AR)          {              try             {                  Socket RSocket = (Socket)AR.AsyncState;                  int REnd = RSocket.EndReceive(AR);                  for (int i = 0; i <  ClientNumb; i++)                  {                      if (ClientSocket[i].Connected)                      {                          ClientSocket[i].Send(MsgBuffer, 0, REnd,0);                      }                      RSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(RecieveCallBack), RSocket);                   }              }              catch { }           }           private void CmdStop_Click(object sender, EventArgs e)          {              ServerThread.Abort();//线程终止              ServerSocket.Close();//关闭SOCKET               this.CmdStar.Enabled = true;              this.CmdStop.Enabled = false;              this.StateMsg.Text = "等待运行";              this.ClientList.Items.Add("服务于 " + DateTime.Now.ToString() + " 停止运行.");          }         }  }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

  • 86.

  • 87.

  • 88.

  • 89.

  • 90.

  • 91.

  • 92.

  • 93.

  • 94.

  • 95.

  • 96.

  • 97.

  • 98.

  • 99.

  • 100.

  • 101.

  • 102.

  • 103.

  • 104.

  • 105.

  • 106.

  • 107.

  • 108.

  • 109.

  • 110.

  • 111.

  • 112.

  • 113.

  • 114.

  • 115.

  • 116.

  • 117.

  • 118.

  • 119.

  • 120.

  • 121.

  • 122.

  • 123.

  • 124.

  • 125.

  • 126.

  • 127.

  • 128.

  • 129.

  • 130.

  • 131.

  • 132.

  • 133.

  • 134.

客户端代码:

复制

 using System;   using System.Collections.Generic;   using System.ComponentModel;   using System.Data;   using System.Drawing;   using System.Text;   using System.Windows.Forms;      using System.Net;   using System.Net.Sockets;   namespace Client  {      public partial class ClientMain : Form      {          public ClientMain()          {              InitializeComponent();          }           private IPEndPoint ServerInfo;          private Socket ClientSocket;          private Byte[] MsgBuffer;          private Byte[] MsgSend;           private void ClientMain_Load(object sender, EventArgs e)          {              this.CmdSend.Enabled = false;              this.CmdExit.Enabled = false;               ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);              MsgBuffer = new Byte[65535];              MsgSend = new Byte[65535];              CheckForIllegalCrossThreadCalls = false;               Random TRand=new Random();              this.UserName.Text = "用户" + TRand.Next(10000).ToString();          }           private void CmdEnter_Click(object sender, EventArgs e)          {              ServerInfo = new IPEndPoint(IPAddress.Parse(this.ServerIP.Text), Convert.ToInt32(this.ServerPort.Text));               try             {                  ClientSocket.Connect(ServerInfo);                   ClientSocket.Send(Encoding.Unicode.GetBytes("用户: " + this.UserName.Text + " 进入系统!\n"));                   ClientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);                   this.SysMsg.Text += "登录服务器成功!\n";                  this.CmdSend.Enabled = true;                  this.CmdEnter.Enabled = false;                  this.CmdExit.Enabled = true;              }              catch             {                  MessageBox.Show("登录服务器失败,请确认服务器是否正常工作!");              }          }           private void ReceiveCallBack(IAsyncResult AR)          {              try             {                  int REnd = ClientSocket.EndReceive(AR);                  this.RecieveMsg.AppendText(Encoding.Unicode.GetString(MsgBuffer, 0, REnd));                  ClientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);               }              catch             {                  MessageBox.Show("已经与服务器断开连接!");                  this.Close();             }           }           private void CmdSend_Click(object sender, EventArgs e)          {             MsgSend = Encoding.Unicode.GetBytes(this.UserName.Text + "说:\n" + this.SendMsg.Text + "\n");              if (ClientSocket.Connected)              {                  ClientSocket.Send(MsgSend);                  this.SendMsg.Text = "";              }              else             {                  MessageBox.Show("当前与服务器断开连接,无法发送信息!");              }          }           private void CmdExit_Click(object sender, EventArgs e)          {              if (ClientSocket.Connected)              {                  ClientSocket.Send(Encoding.Unicode.GetBytes(this.UserName.Text + "离开了房间!\n"));                  ClientSocket.Shutdown(SocketShutdown.Both);                 ClientSocket.Disconnect(false);             }             ClientSocket.Close();              this.CmdSend.Enabled = false;             this.CmdEnter.Enabled = true;             this.CmdExit.Enabled = false;         }          private void RecieveMsg_TextChanged(object sender, EventArgs e)         {             this.RecieveMsg.ScrollToCaret();         }          private void SendMsg_KeyDown(object sender, KeyEventArgs e)         {             if (e.Control && e.KeyValue == 13)             {                 e.Handled = true;                 this.CmdSend_Click(this, null);             }         }         }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

  • 86.

  • 87.

  • 88.

  • 89.

  • 90.

  • 91.

  • 92.

  • 93.

  • 94.

  • 95.

  • 96.

  • 97.

  • 98.

  • 99.

  • 100.

  • 101.

  • 102.

  • 103.

  • 104.

  • 105.

  • 106.

  • 107.

  • 108.

  • 109.

  • 110.

  • 111.

  • 112.

  • 113.

  • 114.

  • 115.

  • 116.

  • 117.

  • 118.

  • 119.

  • 120.

  • 121.

  • 122.

  • 123.

  • 124.

  • 125.

  • 126.

我只对服务器端的代码做了注释,客户端就没有写注释了,因为代码是差不多的。区别在于客户端不需要监听,也不需要启用线程进行委托。

关于 ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

这句代码,我想给初学者解释一下,这里“AddressFamily.InterNetwork”表示的是使用IPV4地址,“SocketType.Stream”表示使用的是流格式(另外还有数据包格式和原始套接字格式),“ProtocolType.Tcp”表示使用TCP协议(另外还有很多其它协议,例如大家常看到的UDP协议)。

服务器端+客户端的聊天系统就介绍完了。另外关于SOCKET类中的BeginReceive方法,请大家参考MSDN,里面有详细说明。

【编辑推荐】

  1. 关于C#知识点总结

  2. C#开发和使用中的33个技巧

  3. SQL Server存储过程介绍

  4. C#下SQL Server 2008表类型参数传递

  5. C#向SQL Server中插入记录时的问题

8    2009-08-18 12:51:19    服务器+客户端