服务器+客户端的聊天程序 - 51CTO.COM

来源:百度文库 编辑:神马文学网 时间:2024/05/01 16:56:01
  • 服务器+客户端的聊天程序

  • http://developer.51cto.com  2009-08-18 12:51  lixyvip  博客园  我要评论(0)
    在当今这样一个网络时代,很多技术都以网络为中心在诞生。本文介绍了服务器端+客户端的聊天系统,希望对大家有用。

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

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

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

    什么是SOCKET套接字?

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

    线程的概念?

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

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

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

     

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

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

    服务器端代码:

            
    1.  using System;  
    2.  using System.Collections.Generic;  
    3.  using System.ComponentModel;  
    4.  using System.Data;  
    5.  using System.Drawing;  
    6.  using System.Text;  
    7.  using System.Windows.Forms;  
    8.    
    9.  using System.Net;  
    10.  using System.Net.Sockets;  
    11.  using System.Threading;  
    12.  using System.Xml;  
    13.    
    14.  namespace Server  
    15.  {  
    16.      public partial class ServerMain : Form  
    17.      {  
    18.          public ServerMain()  
    19.          {  
    20.              InitializeComponent();  
    21.          }  
    22.    
    23.          private void ServerMain_Load(object sender, EventArgs e)  
    24.          {  
    25.              this.CmdStar.Enabled = true;  
    26.              this.CmdStop.Enabled = false;  
    27.          }  
    28.    
    29.          private void 配置参数ToolStripMenuItem_Click(object sender, EventArgs e)  
    30.          {  
    31.              Set TSet = new Set();  
    32.              TSet.ShowDialog();  
    33.          }  
    34.  
    35.          private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)  
    36.          {  
    37.              About TAbout = new About();  
    38.              TAbout.Show();  
    39.          }  
    40.          /// < summary>  
    41.          /// 获得XML文件中的端口号  
    42.          /// < /summary>  
    43.          /// < returns>< /returns>  
    44.          private int GetPort()  
    45.          {  
    46.              try 
    47.              {  
    48.                  XmlDocument TDoc = new XmlDocument();  
    49.                  TDoc.Load("Settings.xml");  
    50.                  string TPort = TDoc.GetElementsByTagName("ServerPort")[0].InnerXml;  
    51.                  return Convert.ToInt32(TPort);  
    52.    
    53.              }  
    54.              catch { return 6600; }//默认是6600  
    55.          }  
    56.    
    57.          //声明将要用到的类  
    58.          private IPEndPoint ServerInfo;//存放服务器的IP和端口信息  
    59.          private Socket ServerSocket;//服务端运行的SOCKET  
    60.          private Thread ServerThread;//服务端运行的线程  
    61.          private Socket[] ClientSocket;//为客户端建立的SOCKET连接  
    62.          private int ClientNumb;//存放客户端数量  
    63.          private byte[] MsgBuffer;//存放消息数据  
    64.    
    65.          private void CmdStar_Click(object sender, EventArgs e)  
    66.          {  
    67.              ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
    68.              ServerInfo=new IPEndPoint(IPAddress.Any,this.GetPort());  
    69.              ServerSocket.Bind(ServerInfo);//将SOCKET接口和IP端口绑定  
    70.              ServerSocket.Listen(10);//开始监听,并且挂起数为10  
    71.    
    72.              ClientSocket = new Socket[65535];//为客户端提供连接个数  
    73.              MsgBuffer = new byte[65535];//消息数据大小  
    74.              ClientNumb = 0;//数量从0开始统计  
    75.    
    76.              ServerThread = new Thread(RecieveAccept);//将接受客户端连接的方法委托给线程  
    77.              ServerThread.Start();//线程开始运行  
    78.    
    79.              CheckForIllegalCrossThreadCalls = false;//不捕获对错误线程的调用  
    80.    
    81.              this.CmdStar.Enabled = false;  
    82.              this.CmdStop.Enabled = true;  
    83.              this.StateMsg.Text = "服务正在运行"+"  运行端口:"+this.GetPort().ToString();  
    84.              this.ClientList.Items.Add("服务于 " + DateTime.Now.ToString() + " 开始运行.");  
    85.          }  
    86.            
    87.          //接受客户端连接的方法  
    88.          private void RecieveAccept()  
    89.          {  
    90.              while (true)  
    91.              {  
    92.                  ClientSocket[ClientNumb] = ServerSocket.Accept();  
    93.                  ClientSocket[ClientNumb].BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(RecieveCallBack),ClientSocket[ClientNumb]);  
    94.                  this.ClientList.Items.Add(ClientSocket[ClientNumb].RemoteEndPoint.ToString()+" 成功连接服务器.");  
    95.                  ClientNumb++;  
    96.              }  
    97.          }  
    98.    
    99.          //回发数据给客户端  
    100.         private void RecieveCallBack(IAsyncResult AR)  
    101.         {  
    102.             try 
    103.             {  
    104.                 Socket RSocket = (Socket)AR.AsyncState;  
    105.                 int REnd = RSocket.EndReceive(AR);  
    106.                 for (int i = 0; i <  ClientNumb; i++)  
    107.                 {  
    108.                     if (ClientSocket[i].Connected)  
    109.                     {  
    110.                         ClientSocket[i].Send(MsgBuffer, 0, REnd,0);  
    111.                     }  
    112.                     RSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(RecieveCallBack), RSocket);  
    113.  
    114.                 }  
    115.             }  
    116.             catch { }  
    117.  
    118.         }  
    119.  
    120.         private void CmdStop_Click(object sender, EventArgs e)  
    121.         {  
    122.             ServerThread.Abort();//线程终止  
    123.             ServerSocket.Close();//关闭SOCKET  
    124.  
    125.             this.CmdStar.Enabled = true;  
    126.             this.CmdStop.Enabled = false;  
    127.             this.StateMsg.Text = "等待运行";  
    128.             this.ClientList.Items.Add("服务于 " + DateTime.Now.ToString() + " 停止运行.");  
    129.         }  
    130.  
    131.  
    132.  
    133.     }  

    客户端代码:

            
    1.  using System;  
    2.  using System.Collections.Generic;  
    3.  using System.ComponentModel;  
    4.  using System.Data;  
    5.  using System.Drawing;  
    6.  using System.Text;  
    7.  using System.Windows.Forms;  
    8.    
    9.  using System.Net;  
    10.  using System.Net.Sockets;  
    11.  
    12. namespace Client  
    13. {  
    14.     public partial class ClientMain : Form  
    15.     {  
    16.         public ClientMain()  
    17.         {  
    18.             InitializeComponent();  
    19.         }  
    20.  
    21.         private IPEndPoint ServerInfo;  
    22.         private Socket ClientSocket;  
    23.         private Byte[] MsgBuffer;  
    24.         private Byte[] MsgSend;  
    25.  
    26.         private void ClientMain_Load(object sender, EventArgs e)  
    27.         {  
    28.             this.CmdSend.Enabled = false;  
    29.             this.CmdExit.Enabled = false;  
    30.  
    31.             ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
    32.             MsgBuffer = new Byte[65535];  
    33.             MsgSend = new Byte[65535];  
    34.             CheckForIllegalCrossThreadCalls = false;  
    35.  
    36.             Random TRand=new Random();  
    37.             this.UserName.Text = "用户" + TRand.Next(10000).ToString();  
    38.         }  
    39.  
    40.         private void CmdEnter_Click(object sender, EventArgs e)  
    41.         {  
    42.             ServerInfo = new IPEndPoint(IPAddress.Parse(this.ServerIP.Text), Convert.ToInt32(this.ServerPort.Text));  
    43.  
    44.             try 
    45.             {  
    46.                 ClientSocket.Connect(ServerInfo);  
    47.  
    48.                 ClientSocket.Send(Encoding.Unicode.GetBytes("用户: " + this.UserName.Text + " 进入系统!\n"));  
    49.  
    50.                 ClientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);  
    51.  
    52.                 this.SysMsg.Text += "登录服务器成功!\n";  
    53.                 this.CmdSend.Enabled = true;  
    54.                 this.CmdEnter.Enabled = false;  
    55.                 this.CmdExit.Enabled = true;  
    56.             }  
    57.             catch 
    58.             {  
    59.                 MessageBox.Show("登录服务器失败,请确认服务器是否正常工作!");  
    60.             }  
    61.         }  
    62.  
    63.         private void ReceiveCallBack(IAsyncResult AR)  
    64.         {  
    65.             try 
    66.             {  
    67.                 int REnd = ClientSocket.EndReceive(AR);  
    68.                 this.RecieveMsg.AppendText(Encoding.Unicode.GetString(MsgBuffer, 0, REnd));  
    69.                 ClientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);  
    70.  
    71.             }  
    72.             catch 
    73.             {  
    74.                 MessageBox.Show("已经与服务器断开连接!");  
    75.                 this.Close();  
    76.            }  
    77.  
    78.         }  
    79.  
    80.         private void CmdSend_Click(object sender, EventArgs e)  
    81.         {  
    82.            MsgSend = Encoding.Unicode.GetBytes(this.UserName.Text + "说:\n" + this.SendMsg.Text + "\n");  
    83.             if (ClientSocket.Connected)  
    84.             {  
    85.                 ClientSocket.Send(MsgSend);  
    86.                 this.SendMsg.Text = "";  
    87.             }  
    88.             else 
    89.             {  
    90.                 MessageBox.Show("当前与服务器断开连接,无法发送信息!");  
    91.             }  
    92.         }  
    93.  
    94.         private void CmdExit_Click(object sender, EventArgs e)  
    95.         {  
    96.             if (ClientSocket.Connected)  
    97.             {  
    98.                 ClientSocket.Send(Encoding.Unicode.GetBytes(this.UserName.Text + "离开了房间!\n"));  
    99.                 ClientSocket.Shutdown(SocketShutdown.Both);  
    100.                ClientSocket.Disconnect(false);  
    101.            }  
    102.            ClientSocket.Close();  
    103.  
    104.            this.CmdSend.Enabled = false;  
    105.            this.CmdEnter.Enabled = true;  
    106.            this.CmdExit.Enabled = false;  
    107.        }  
    108.  
    109.        private void RecieveMsg_TextChanged(object sender, EventArgs e)  
    110.        {  
    111.            this.RecieveMsg.ScrollToCaret();  
    112.        }  
    113.  
    114.        private void SendMsg_KeyDown(object sender, KeyEventArgs e)  
    115.        {  
    116.            if (e.Control && e.KeyValue == 13)  
    117.            {  
    118.                e.Handled = true;  
    119.                this.CmdSend_Click(thisnull);  
    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,里面有详细说明。