C# Socket网络编程之客户端群发消息

本文介绍了一个基于Socket的多客户端聊天服务器的设计与实现方案。服务器能够接收多个客户端连接,并实现客户端间的消息广播功能。通过使用线程管理和客户端信息集合来确保高效稳定的通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接上一片博客,接着socket的学习。此次写的是服务器端被多个客户端连接,并且一个客户端发消息,其他连接的客户端都可接收到。
服务器端设计思路:
1.要有一个线程监听端口,当有客户端连接上时,就要产生一个socket对象负责和这个客户端通信,此时需要开启一个线程处理与这个客户端的通信。
2.转发给其他客户端时,需要知道所有连接客户端的信息。所以建立一个集合,保存连接客户端信息
3.创建一个客户端集合类,能够添加客户端信息,同时当一个客户端离开后能够从集合中移除信息
4.创建一个接受客户端消息的类,能够接受产生的socket的实例对象
ClientGeneric类:
class ClientGeneric
{
   private Dictionary<string,Socket> clientDic=new Dictionary<string,Socket>();
   private static ClientGeneric cg=new ClientGeneric();//单例模式,保证各个线程访问同一个对象
   public static ClientGeneric Instance()
   {
    return cg;
   }
   //将连接的客户端信息和产生的socket对象加入集合中
   public void AddClient(string key,Socket socket)
   {
      clientDic.Add(key,socket);
   }
   //当一个客户端离开后移除集合中客户端信息与产生的socket对象
   public void RemoveClient(string key)
   {
      clientDic.Remove(key);
   }
   //群聊是发送消息,遍历集合中客户端信息,为每一个客户端发送消息
   public void SendMsg(string msg)
   {
     byte[] msgBytes=Encoding.ASCII.GetBytes(msg.ToCharArray());
     foreach(var kvp in clientDic)
     {
     kvp.Value.Send(msgBytes);
     }
   }
}

服务器端接受客户端会话处理类ServerSession:
class ServerSession
{
   private Socket socket;
   public ServerSession(Socket socket)
   {
      this.socket=socket;
   }
   public void GetMsg()
   {
      string remoteEndPoint=socket.RemoteEndPiont.ToString();//获取连接客户端的信息
      ClientGeneric.Instance().AddClient(remoteEndPiont,socket);
      string msg=string.Empty;
      byte[] bytes=new byte[1024*1024];
      int len=0;
      while(true)//循环获取客户端发来的消息
      {
        len=socket.Receive(bytes);
        msg=Encoding.UTF8.GetString(bytes,0,len);
        if(msg.Equals("End"))
        {
           ClientGeneric.Instance().Remove(remoteEndPoint);//从集合中移除断开的客户端信息
           Thread.CurrentThread.Abort();//停止当前监听的线程
           socket.Close();
        }
        //将收到的信息进行转发给其他客户端
        ClientGeneric.Instance().SendMsg(msg);
        
      }

   }
}

服务器监听类:
public partial class ServerForm
{
        Socket socket_Server = null; //定义一个套接字接口对象,并初始化值为空
        Thread myThread = null; //定义一个线程对象,并初始化值为空        
        Socket socket_Connet = null; //用于与客户端连接       
        string RemoteEndPoint; //客户端的网络结点
        private void buttonStartListen_Click(object sender, EventArgs e)
        {
            socket_Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //new一个Socket对象,注意这里用的是流式Socket(针对于面向连接的TCP服务应用)而不是数据报式Socket(针对于面向无连接的UDP服务应用)。
            string IP = textBoxIP.Text.Trim();
            IPAddress ServerIP = IPAddress.Parse(IP); //提取IP地址
            int port = int.Parse(textBoxPort.Text.Trim()); //port是端口号
            IPEndPoint point = new IPEndPoint(ServerIP, port); //point为网络结点对象
            socket_Server.Bind(point); //将结点绑定到套接字上
            socket_Server.Listen(10); //设置连接队列的最大长度,可根据服务器的性能,可以设置更大程度。
            textBoxListenMsg.AppendText("监听成功!\t\n");
            
            myThread = new Thread(Listen_Disp);
            myThread.IsBackground = true; //设置是否为后台线程,设置后台线程是为了使当关闭窗口时所有其他线程关闭
            myThread.Start();

        }

        void Listen_Disp()
        {
            while (true)
            {
                socket_Connet = socket_Server.Accept();
                //当收到一个客户端连接,就产生一个socket负责与其通信,并开启一个线程管理这个客户端
                ServerSession ss = new ServerSession(socket_Connet);
                Thread t= new Thread(ss.GetMsg);
                t.Start();
                t.IsBackground = true;

                RemoteEndPoint = socket_Connet.RemoteEndPoint.ToString(); //客户端网络结点号
                textBoxListenMsg.AppendText("成功与" + RemoteEndPoint + "客户端建立连接!\t\n"); //显示与客户端连接情况               
                OnlineList_Disp(RemoteEndPoint); //显示在线客户端                

            }
        }

       
        void OnlineList_Disp(string Info)
        {
            listBoxOnlineList.Items.Add(Info); //在线列表中显示连接的客户端套接字
        }
}

客户端接收发送消息:
 public partial class Form1 : Form
    {
        Socket socket = null; //定义一个套接字,初始化为空
        Thread thread = null; //定义一个线程  
        IPEndPoint point = null;

        public Form1()
        {
            InitializeComponent();
            RichTextBox.CheckForIllegalCrossThreadCalls = false; //允许跨线程访问
        }

        private void buttonConnectToServer_Click(object sender, EventArgs e)
        {
            string IP = textBoxIP.Text.Trim();
            int port = int.Parse(textBoxPort.Text.Trim());
            IPAddress ip = IPAddress.Parse(IP);
            point = new IPEndPoint(ip, port); //网络结点对象
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //初始化套接字
            socket.Connect(point);//连接给定的IP地址和端口号
            thread = new Thread(ShowMsg); //开启一个监听线程,监听服务器端发来的数据
            thread.IsBackground = true; //后台线程
            thread.Start();
            OnlineList_Disp(textBoxIP.Text.Trim());
        }

        void OnlineList_Disp(string Info)
        {
            listBoxOnlineList.Items.Add(Info); //在线列表中显示连接的客户端套接字
        }
        void ShowMsg()
        {
            byte[] bytes = new byte[1024 * 1024 * 3]; //设置字节流数组为3M
            int length = 0;
            string Msg = string.Empty;
            while (true)
            {
                length = socket.Receive(bytes);
                Msg = System.Text.Encoding.UTF8.GetString(bytes, 0, length); //注意要把字节转化为字符串
                richTextBoxReceiveMsg.AppendText("服务器端:"+Msg+"\t\n"); //显示接收的信息             

            }
        }
        void Receive_Show(string Info)
        {
            richTextBoxReceiveMsg.AppendText(Info + "\t\n");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string sendMsg = richTextBoxMsg.Text.Trim(); //要发送的信息
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg); //将要发送的信息转化为字节数组,因为Socket发送数据时是以字节的形式发送的
            socket.Send(bytes); //发送数据
            richTextBoxReceiveMsg.AppendText("客户端:"+sendMsg+"\t\n");
            richTextBoxMsg.Text = "";

        }

        private void button_Interput_Click(object sender, EventArgs e)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("End"); //将要发送的信息转化为字节数组,因为Socket发送数据时是以字节的形式发送的
            socket.Send(bytes); //发送数据
            thread.Abort();//将监听线程停止,不在接听服务器端发来的数据
            socket.Close();
        }


    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值