基於C# Winform的簡易聊天程序[socket-信息羣發]

原理

首先我們需要獲取連接客戶端的IP和Port,並添加到客戶端列表裏作爲每個客戶端的唯一標識.然後通過相應客戶端的Socket.Send()方法將信息發送出去.

服務端給客戶端的信息羣發與服務端給單個客戶端的信息發送原理是一樣的,通過遍歷客戶端列表裏的所有客戶端標識,然後把信息一個個發送出去.

 

界面設計 - 客戶端

Client-UI

 

界面設計 - 服務端

Server-UI

 

代碼實施 - 客戶端

客戶端沒有做什麼功能改進,這裏就不貼代碼了,需要看的學友可以到隨筆後面下載源代碼.

 

代碼實施 - 服務端

這裏將手動輸入服務端IPv4地址改爲了程序自動獲取

       /// <summary>
       /// 獲取本地IPv4地址
       /// </summary>
       /// <returns>本地IPv4地址</returns>
       public IPAddress GetLocalIPv4Address()
       {
           IPAddress localIPv4 = null;
           //獲取本機所有的IP地址列表
           IPAddress[] ipAddressList = Dns.GetHostAddresses(Dns.GetHostName());
           foreach (IPAddress ipAddress in ipAddressList)
           {
               //判斷是否是IPv4地址
               if (ipAddress.AddressFamily == AddressFamily.InterNetwork) //AddressFamily.InterNetwork表示IPv4 
               {
                   localIPv4 = ipAddress;
               }
               else
                   continue;
           }
           return localIPv4;
       }

爲了方便後期給所有訪問的客戶端羣發信息,我們需要用過通過監聽客戶端來獲取所有訪問客戶端的IP地址和端口號,並組成每個訪問客戶端的唯一標識clientName 用於顯示在客戶端列表上;客戶端唯一標識還有個作用就是服務端可以選擇性的給單獨某個客戶端發送信息.

        //用於保存所有通信客戶端的Socket
        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

        //創建與客戶端建立連接的套接字
        Socket socConnection = null;
        string clientName = null; //創建訪問客戶端的名字
        IPAddress clientIP; //訪問客戶端的IP
        int clientPort; //訪問客戶端的端口號
        /// <summary>
        /// 持續不斷監聽客戶端發來的請求, 用於不斷獲取客戶端發送過來的連續數據信息
        /// </summary>
        private void WatchConnecting()
        {
            while (true)
            {
                try
                {
                    socConnection = socketWatch.Accept();
                }
                catch (Exception ex)
                {
                    txtMsg.AppendText(ex.Message); //提示套接字監聽異常
                    break;
                }
                //獲取訪問客戶端的IP
                clientIP = (socConnection.RemoteEndPoint as IPEndPoint).Address;
                //獲取訪問客戶端的Port
                clientPort = (socConnection.RemoteEndPoint as IPEndPoint).Port;
                //創建訪問客戶端的唯一標識 由IP和端口號組成 
                clientName = "IP: " + clientIP +" Port: "+ clientPort;
                lstClients.Items.Add(clientName); //在客戶端列表添加該訪問客戶端的唯一標識
                dicSocket.Add(clientName, socConnection); //將客戶端名字和套接字添加到添加到數據字典中

                //創建通信線程 
                ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg);
                Thread thread = new Thread(pts);
                thread.IsBackground = true;
                //啓動線程
                thread.Start(socConnection);
                txtMsg.AppendText("IP: " + clientIP + " Port: " + clientPort + " 的客戶端與您連接成功,現在你們可以開始通信了...\r\n");
            }
        }

服務端向客戶端發送信息,在沒有選擇具體某個客戶端的情況下,默認羣發. 如果選擇了具體某個客戶端,則單獨向該客戶端發送信息.

       /// <summary>
       /// 發送信息到客戶端的方法
       /// </summary>
       /// <param name="sendMsg">發送的字符串信息</param>
       private void ServerSendMsg(string sendMsg)
       {
           sendMsg = txtSendMsg.Text.Trim();
           //將輸入的字符串轉換成 機器可以識別的字節數組
           byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendMsg);
           //向客戶端列表選中的客戶端發送信息
           if (!string.IsNullOrEmpty(lstClients.Text.Trim())) 
           {
               //獲得相應的套接字 並將字節數組信息發送出去
               dicSocket[lstClients.Text.Trim()].Send(arrSendMsg);
               //通過Socket的send方法將字節數組發送出去
               txtMsg.AppendText("您在 " + GetCurrentTime() + " 向 IP: " + clientIP + " Port: " + clientPort + " 的客戶端發送了:\r\n" + sendMsg + "\r\n");
           }
           else //如果未選擇任何客戶端 則默認爲羣發信息
           {
               //遍歷所有的客戶端
               for (int i = 0; i < lstClients.Items.Count; i++)
               {
                   dicSocket[lstClients.Items[i].ToString()].Send(arrSendMsg);
               }
               txtMsg.AppendText("您在 " + GetCurrentTime() + " 羣發了信息:\r\n" + sendMsg + " \r\n");
           }
       }

運行程序

1.首先啓動服務端並連接各個客戶端 

1-server

 

1-client1

 

1-client2

 

2.服務端向所有客戶端羣發信息

2-server

 

2-client1

 

2-client2

 

3.向指定的客戶端發送信息

3server

 

3-client2

這樣,服務端向客戶端羣發信息的功能就做好了.如果大家感興趣,可以結合第2篇-文件發送 來做個服務端向客戶端羣發文件的功能 :)

發佈了49 篇原創文章 · 獲贊 55 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章