zoukankan      html  css  js  c++  java
  • C#下如何实现服务器+客户端的聊天程序

    最近也在接触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, 0new 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, 0new 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     }
    134 }

    客户端代码:

      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, 0new 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, 0new 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     }
    127 }

    我只对服务器端的代码做了注释,客户端就没有写注释了,因为代码是差不多的。区别在于客户端不需要监听,也不需要启用线程进行委托。
    关于 ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    这句代码,我想给初学者解释一下,这里“AddressFamily.InterNetwork”表示的是使用IPV4地址,“SocketType.Stream”表示使用的是流格式(另外还有数据包格式和原始套接字格式),“ProtocolType.Tcp”表示使用TCP协议(另外还有很多其它协议,例如大家常看到的UDP协议)。

    另外关于SOCKET类中的BeginReceive方法,请大家参考MSDN,里面有详细说明。

    希望本人给的这个程序可以起到一个抛砖引玉的作用,不明白之处可以加QQ(17020415)或留言。

    备注:

    //2007-12-01

    //今天有朋友加我QQ问我有关服务端“Settings.xml”文件的内容部分,我现在把内容贴出来,其实很简单,就是方便服务端修改端口的。

    <?xml version="1.0" encoding="utf-8" ?> 
    <Server>
      
    <ServerPort>6600</ServerPort>
    </Server>

    完整的源码我已经放在CSDN上面共享了,地址:http://download.csdn.net/user/lixyvip
  • 相关阅读:
    Java 实现 蓝桥杯 生兔子问题
    Java实现 蓝桥杯 基因牛的繁殖
    Java实现 蓝桥杯 基因牛的繁殖
    Java实现 蓝桥杯 基因牛的繁殖
    Java实现 LeetCode 33 搜索旋转排序数组
    Java实现 LeetCode 33 搜索旋转排序数组
    Java实现 LeetCode 33 搜索旋转排序数组
    深入探究VC —— 资源编译器rc.exe(3)
    深入探究VC —— 编译器cl.exe(2)
    深入探究VC —— 编译器cl.exe(1)
  • 原文地址:https://www.cnblogs.com/4kapple/p/1295771.html
Copyright © 2011-2022 走看看