C# 簡單的聊天大廳功能及原始碼(socket通訊)

fwl562213140發表於2020-10-17

一、前言起因

最近突然對socket通訊產生了興趣。於是簡單的研究了一下,下面將研究的東西用最簡單的大白話寫出來與大家分享下。比較淺顯,大神就別浪費時間看下面的內容了。

二、簡單介紹

socket:插座、插孔,這裡代表一種使用tcp或udp協議的簡單雙向通訊連線(即“”套接字“”,我個人就理解為私人固定電話與電話公司。下方文字為專業描述,括號裡的用固話和電話公司來比喻描述,可能不太準確望大神指教。)。主要包含客戶端和服務端,其最簡單的應用就是用於客戶端跟服務端進行通訊。
服務端(電話公司):先初始化Socket(建立公司),為其繫結IP和埠以便客戶端連線(bind,釋出電話公司聯絡方式),同時對其進行實時監聽(listen,等待家用電話辦理業務或來電諮詢),呼叫阻塞等待客戶端連線或發來訊息(accept,安排好客服)。
客戶端(家用固話):先初始化Socket(購買電話機),然後連線到伺服器(connect,去電話公司開戶,辦理電話線),同時服務端會給客戶端分配好連線埠(電話公司給家用固話分配電話號)。當然,客戶端也可以主動繫結未被佔用的埠(主動申請挑選靚號),但是並不推薦(辦理麻煩,同時可能辦理的號碼已經有人在用了)。
雙方通訊(溝通過程):如果連線伺服器成功(固話辦理成功,並分配好了電話號),客戶端則可以向服務端傳送資料,服務端同時也可以對接收到的內容進行處理並返回給客戶端(固話跟電話公司進行諮詢溝通),完成所有需要的操作後(所有諮詢溝通完畢),關閉連線完成通訊(結束通話電話)。如果連線未成功(辦理固話失敗了),則會引發連線異常(光買了電話,但是沒有電話線。。。)。

三、多人聊天大廳擴充套件思路

上述的連線過程為服務端與客戶端一對一來進行的。那我們有沒有什麼辦法可以多人一起進行聊天呢。當然是可以的,辦法很簡單,就是在服務端做一個訊息分發功能(電話公司的公告或廣播)。當有很多客戶端連線進來時(很多電話同時連線在電話公司中),一個客戶端給服務端傳送了訊息(甲用電話給電話公司留了言),那麼服務端則利用分發功能,將該客戶端發來的訊息同時分發給其他連線在服務端的客戶端(客戶公司將甲電話的留言,迴圈傳送給當時線上的乙電話、丙電話……)。那麼問題又來了,服務端如何儲存所有連線的客戶端資訊呢(電話公司如何儲存客戶資訊)。其實也很簡單,建立一個客戶端socket列表(電話公司的客戶資訊檔案),每當一個客戶端跟服務端連線成功時,服務端就主動的將客戶端socket儲存進列表(新使用者新增入檔案),當客戶端斷開時,在將其從列表中移除就即可(拆機的使用者從檔案中刪除)。以上就是這個demo所實現的思想,可能舉例不太準確,但就是個輔助理解的東西。望大家勿怪、勿噴。

四、核心方法程式碼

		/// <summary>
        /// 廣播資訊
        /// </summary>
        /// <param name="useStr">傳入收到的傳輸的內容</param>
        /// <param name="obj">傳送資訊的客戶</param>
        /// <param name="isSendSelf">是否推送給自己</param>
        /// <param name="isServerSelf">是否為伺服器推送</param>
        /// <returns>返回處理後的廣播訊息文字</returns>
        private string Broadcast(string userStr, object obj,bool isSendSelf,bool isServerSelf)
        {
            Socket clientSend = obj as Socket; //當前傳送資訊的客戶
            string rtnMessage = "";
            try
            {
                foreach (Socket client in userList)
                {
                    if (!isSendSelf)    //不推送自己
                    {
                        if (client != clientSend)//將資訊廣播給其他使用者
                        {
                            if (!isServerSelf)  //非伺服器推送
                            {
                                rtnMessage = IPToAddress(clientSend) + ":" + userStr;
                                client.Send(Encoding.Default.GetBytes(rtnMessage));
                            }
                            else    //伺服器不推送伺服器IP和埠,只推送“伺服器”
                            {
                                rtnMessage = "【伺服器】:" + userStr;
                                client.Send(Encoding.Default.GetBytes(rtnMessage));
                            }
                        }
                    }
                    else    //推送自己
                    {
                        if (!isServerSelf)//非伺服器推送
                        {
                            rtnMessage = IPToAddress(clientSend) + ":" + userStr;
                            client.Send(Encoding.Default.GetBytes(rtnMessage));
                        }
                        else   //伺服器不推送伺服器IP和埠,只推送“伺服器”
                        {
                            rtnMessage = "【伺服器】:" + userStr;
                            client.Send(Encoding.Default.GetBytes(rtnMessage));
                        }
                    }
                }
            }
            catch (Exception e)
            {
                userList.Remove(clientSend);    //移除退出客戶
                //Thread.CurrentThread.Abort();//退出時掐死執行緒,不然遞迴反彈
            }
            return rtnMessage;
        }


		/// <summary>
        /// 監聽連線
        /// </summary>
        private void Accept()
        {
            //接受連線
            Socket clientSocket = socketSevice.Accept();
            userList.Add(clientSocket); //將連線的客戶端存入列表
            string clientMess = "【伺服器】(" + DateTime.Now.ToString("HH:mm:ss")+")分配給您的埠為:(" + (clientSocket.RemoteEndPoint as IPEndPoint).Port.ToString() + ")";    //拼接分配埠號字串
            clientSocket.Send(Encoding.Default.GetBytes(clientMess)); //將分配資訊反饋給連線的客戶端

            string mess = IPToAddress(clientSocket) + ":連線進來了";    //廣播登入資訊的客戶端
            Console.WriteLine(mess);    //同步在服務端控制檯顯示
            Broadcast(mess, clientSocket, false,true);    //服務端廣播,客戶端連線訊息(不廣播給自己) 
            Thread RecvThread = new Thread(ReceMessage);    //將接收客戶端訊息加入程式
            RecvThread.IsBackground = true;
            RecvThread.Start(clientSocket);

            Accept();//遞迴
        }

五、截圖

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

六、原始碼包

下載地址:https://download.csdn.net/download/fwl562213140/12948324
說明:
一、伺服器預設地址為:192.168.15.139,埠為:8888 。如需修改,可在服務端原始碼頂端的屬性中進行修改。
二、客戶端開啟後,預設為服務端連線地址賦值。如需修改,可在客戶端原始碼頂端的屬性中進行修改。
三、客戶端連線後,服務端自動將分配給客戶端的埠號返回客戶端。客戶端解析後新增到標題欄。(該處根據需要,可以自行修改為返回IP地址等連線資訊)
四、該demo由於只是為了實現簡單的聊天大廳功能,所以未考慮粘包的情況。如果需要考慮請自行新增。參考地址:https://blog.csdn.net/weixin_30379911/article/details/97265907
五、開發環境為VS2015,服務端使用控制檯,客戶端使用Winform進行編寫
六、本demo包中包含服務端、客戶端的開發原始碼以及生成後的可執行檔案。

七、轉載說明

碼字不易,轉載望留痕。
原文出處:https://blog.csdn.net/fwl562213140/article/details/109133059

相關文章