UDP實現一個簡易的聊天室(多個主機連接終端) 已完善

来源:https://www.cnblogs.com/ASsss/archive/2019/03/01/10457175.html
-Advertisement-
Play Games

效果展示 網路編程 --使用UDP協議的簡單聊天室 由於TCP協議是一種面向連接的協議,有三次揮手通信確認機制,且數據包沒有代銷限制,TCP協議確保在通信雙方都收到對方確認信息的前提下,才開始為通信的雙方傳輸信息(數據包)! 這樣數據包的傳輸可以得到安全保障!所以簡單的理解為安全的!當然一旦,出現網 ...


 效果展示 

 

 

網路編程 --使用UDP協議的簡單聊天室

由於TCP協議是一種面向連接的協議,有三次揮手通信確認機制,且數據包沒有代銷限制,TCP協議確保在通信雙方都收到對方確認信息的前提下,才開始為通信的雙方傳輸信息(數據包)!

這樣數據包的傳輸可以得到安全保障!所以簡單的理解為安全的!當然一旦,出現網路問題,或者一些其他意外現象造成通信雙方的連接出現異常或斷開連接,使用TCP是不能傳輸信息的!

UDP不是一種面向連接的協議,就是說,在使用UDP協議進行數據交互的時候,彼此可以不連接,通信的一端突然地向另外一端發送數據包,但是對方沒有啟動接收程式,那麼對方當時是收不到數據包的,或者當你發送數據的過程中,突然出現意外斷網,停電等等意外現象,都有可能造成對方收不到信息!也就說,你發送的信息對方沒收到,同時你也不知道對方有沒有收到!這不好!

 

載入場景

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Text;
using Common;
using UnityEngine.UI;
using System;
using System.Net;
using UIWidgetsSamples;
using UnityEngine.SceneManagement;

namespace  NS
{
    ///<summary>
    /// 程式入口
    ///</summary>
    public class GameMain : MonoSingleton<GameMain>
    {

        private InputField IPInputField;

        private InputField IPInputField1;
        //點擊按鈕 ButtonClientEnter初始化客戶端服務類
        private void Start()
        {
            transform.FindChildByName("ButtonClientEnter").
                GetComponent<Button>().onClick.AddListener(OnEnterChatScene);
            //獲取進入按鈕
            transform.FindChildByName("ButtonServerEnter").
                GetComponent<Button>().onClick.AddListener(OnEnterServerScene);
            // InputServerIPForClient
            IPInputField1 = transform.FindChildByName("" +
                "InputServerIPForClient").GetComponent<InputField>();
            IPInputField = transform.FindChildByName("" +
                "InputServerIPForServer").GetComponent<InputField>();
            //獲取文本框  拿到IP
        }

        private void OnEnterServerScene()
        {
            UDPServerNetWorkService.Instance.Initialized(IPInputField.text);
            SceneManager.LoadScene("Server");
        }

        //進去聊天室
        private void OnEnterChatScene()
        {
            UDPClientNetWorkService.Instance.Initialized 
                (IPInputField1.text);
            //獲取IP  初始化客戶都安
            SceneManager.LoadScene("Chat");
            //切換到聊天視窗 載入不刪除 
        }

        //載入場景
    }
}
GameMain

 

Date數據類

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using System.Net.Sockets;
using System.Text;
using Common;
using UnityEngine.UI;
using System;
using System.Net;
using UIWidgetsSamples;
using System.Runtime.Serialization.Formatters.Binary;

namespace  NS
{
    ///<summary>
    ///聊天消息
    ///</summary>
    [System.Serializable]//表示類可以被序列化
    public class ChatMessage 
    {
        //消息類型 0 1 2 枚舉
        public UDPNetWork Type { get; set; }
        //發送者名稱
        public string SenderName { get; set; }
        //消息內容
        public string Content { get; set; }


        //如何把一個對象轉位元組數組???
        //序列化:將對象狀態存儲到某種介質的過程(場景還原,網路交互)
        //存儲介質:磁碟  記憶體   網路
        //反序列化:將某種介質中的對象轉換成C#對象
        public  byte []  ObjectToBytes()
        {
            //1.二進位寫入器  往記憶體流去寫  支持跨平臺
            //MemoryStream ms = new MemoryStream();
            //BinaryWriter writer = new BinaryWriter(ms);

            //byte[] bys = Encoding.UTF8.GetBytes(SenderName);
            ////值類型  因為大小固定  所以直接Write
            ////引用類型  大小不固定  所以需要寫入長度
            //writer.Write(bys.Length);
            ////寫入長度
            //writer.Write(bys);
            //寫入內容
            //2.序列化
            //使用Using  可以在退出代碼塊的時候 自動關閉非托管資源
            using (MemoryStream ms = new MemoryStream())
            {
                //記憶體流
                BinaryFormatter fomatter = new BinaryFormatter();
                //二進位格式化器
                fomatter.Serialize(ms, this);
                //序列化  將當前對象序列化到記憶體流中                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

                //byte[] result = ms.ToArray();
                //從記憶體流中獲取位元組數組
                return ms.ToArray();
            }
        }
        public static  ChatMessage   BytesToObject(byte [] bytes)
        {
            using (MemoryStream ms = new MemoryStream(bytes))
            {
                //記憶體流
                BinaryFormatter fomatter = new BinaryFormatter();
                //二進位格式化器
                return fomatter.Deserialize(ms) as ChatMessage;
                //反序列化  將記憶體流中  中的位元組反序列化                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

            }
            //自動釋放資源
        }
    }
}
ChatMessage
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Net;

namespace  NS
{
    ///<summary>
    /// 事件參數類 
    ///</summary>
    public class MessageArrivedEventArgs
    {
        public  ChatMessage Message { get; set; }
        public DateTime DateTime { get; set; }

        public IPEndPoint senderEP { get; set; }

    }
}
MessageArrivedEventArgs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace  NS
{
    ///<summary>
    /// 消息類型
    ///</summary>
    public enum UDPNetWork
    {
        Online,
        //上線
        Offline,
        //下線
        General
        //普通
    }
}
UDPNetWork

 

NetWork Service(網路服務)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Common;
using System.Net.Sockets;
using System.Text;
using UnityEngine.UI;
using System.Net;
using UIWidgetsSamples;
using System.Threading;
namespace  NS
{
    ///<summary>
    ///基於UDP協議  客戶端網路服務類
    ///</summary>
    public class UDPClientNetWorkService : MonoSingleton<UDPClientNetWorkService>
    {
        //事件參數類  傳遞信息
        public event Action<MessageArrivedEventArgs> MessageArrivedEventHandler;
        //初始化socket對象  ,由開始界面的Game Main類調用
        private Thread receiverThread;
        //線程
        private UdpClient udpServer;
        public void Initialized(string serverIP)
        {
            
            //載入不刪除對象
            udpServer = new UdpClient();
            //客戶端發送消息再給終結點
            serverEP = new IPEndPoint(IPAddress.Parse(serverIP), 8989);
            Debug.Log(serverEP.Address);

            //分配IP和埠  沒有保存
            udpServer.Connect(serverEP);
            //Connect方法建立預設遠程主機使用中指定的值endPoint參數。 
            //一旦建立,無需在每次調用中指定遠程主機Send方法。

            receiverThread = new Thread(ReceiveMessage);
            receiverThread.Start();
            //提示上線
            SendChatMessage(new ChatMessage() { Type = UDPNetWork.Online });
        }
        private IPEndPoint serverEP;
        //發送消息  send按鈕
        public void SendChatMessage(ChatMessage msg)
        {
            byte[] dgram = msg.ObjectToBytes();
            //獲取報文
            udpServer.Send(dgram, dgram.Length);
            //發送需要埠和IP
            
            Debug.Log(msg.Type);
        }
        //接收消息  接收阻塞  線程
        public void ReceiveMessage()
        {
            while (true)//不停接收數據
            {
                //接收
                IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
                byte[] date = udpServer.Receive(ref remote);
                ChatMessage msg = ChatMessage.BytesToObject(date);
                Debug.Log(msg.Type);
                //引發事件
                if (MessageArrivedEventHandler != null)
                {
                    //線程交叉助手類調用 因為訪問UnityAPI
                    ThreadCrossHelper.Instance.ExecuteOnMainThread(() =>
                    {
                        var args = new MessageArrivedEventArgs()
                        {
                            Message = msg,
                            DateTime = DateTime.Now
                        };
                    //創建事件參數類  參數沒有賦值???
                    MessageArrivedEventHandler(args);
                    //調用方法不需要傳參數嗎???
                });
                }

            }
        }
        //關閉
        public void OnApplicationQuit()
        {
            SendChatMessage(new ChatMessage() { Type = UDPNetWork.Offline });
            receiverThread.Abort();
            udpServer.Close();
        }
    }
}
UDPClientNetWorkService
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Common;
using System.Net.Sockets;
using System.Text;
using UnityEngine.UI;
using System.Net;
using UIWidgetsSamples;
using System.Threading;
using System;
namespace  NS
{
    ///<summary>
    /// 基於UDP的服務端網路服務類
    ///</summary>
    public class UDPServerNetWorkService : MonoSingleton<UDPServerNetWorkService>
    {
        //客戶端列表
        //初始化Socket
        //發送消息
        //接收消息 
        //事件參數類  傳遞信息
        public event Action<MessageArrivedEventArgs> MessageArrivedEventHandler;
        //初始化socket對象  ,由開始界面的Game Main類調用
        private Thread receiverThread;
        //線程
        private UdpClient udpServer;
        public void Initialized(string serverIP)
        {
            //載入不刪除對象
            //客戶端發送消息再給終結點
            serverEP = new IPEndPoint(IPAddress.Parse(serverIP), 8989);
            udpServer = new UdpClient(serverEP);

            receiverThread = new Thread(ReceiveMessage);
            receiverThread.Start();


            //註冊事件  收到消息的時候執行
            MessageArrivedEventHandler += OnMessageArrived;
        }
        //收到消息的時候分發
        private void OnMessageArrived(MessageArrivedEventArgs obj)
        {
            switch (obj.Message.Type)
            {
                case UDPNetWork.Online:
                    //存列表
                    AddClient(obj.senderEP);
                    break;
                case UDPNetWork.Offline:
                    //移除列表
                    RemoveClient(obj.senderEP);
                    break;
                case UDPNetWork.General:
                    //轉發
                    TransmitMessage(obj.Message);
                    break;
            }
        }

        private IPEndPoint serverEP;
        //發送消息  send按鈕
        public void SendChatMessage(ChatMessage msg,IPEndPoint remote)
        {
            byte[] dgram = msg.ObjectToBytes();
            //獲取報文
            udpServer.Send(dgram, dgram.Length, remote);
            //發送需要埠和IP
        }
        //接收消息  接收阻塞  線程
        public void ReceiveMessage()
        {
            while (true) //不停接收數據
            {

                //接收
                IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
                byte[] date = udpServer.Receive(ref remote);
                ChatMessage msg = ChatMessage.BytesToObject(date);
                Debug.Log(msg.Type + "adsadad");
                //引發事件
                if (MessageArrivedEventHandler != null)
                {
                    //線程交叉助手類調用 因為訪問UnityAPI
                    ThreadCrossHelper.Instance.ExecuteOnMainThread(() =>
                    {
                        var args = new MessageArrivedEventArgs()
                        {
                            Message = msg,
                            DateTime = DateTime.Now,
                            senderEP = remote
                            
                        };
                        Debug.Log(msg + "1");
                    //創建事件參數類  參數沒有賦值???
                    MessageArrivedEventHandler(args);
                        //調用方法不需要傳參數嗎???
                        Debug.Log(msg + "2");
                    });
                }
            }
        }
        //關閉
        public void OnApplicationQuit()
        {
            receiverThread.Abort();
            udpServer.Close();
        }

        private List<IPEndPoint> allListEP = new List<IPEndPoint>();
        //添加客戶端
        public  void AddClient(IPEndPoint clientEP)
        {
            allListEP.Add(clientEP);
        }
        //移除客戶端
        public void RemoveClient(IPEndPoint clientEP)
        {
            allListEP.Remove(clientEP);
        }
        //轉發消息
        private void  TransmitMessage(ChatMessage msg)
        {
            foreach (var item in allListEP)
            {
                SendChatMessage(msg, item);
                //根據不同埠發送消息
            }
        }
    }
}
UDPServerNetWorkService
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Text;
using Common;
using UnityEngine.UI;
using System;
using System.Net;
using UIWidgetsSamples;
namespace  NS
{
    ///<summary>
    ///客戶端顯示信息界面類
    ///</summary>
    public class ChatClient : MonoBehaviour
    {
        private InputField messageInput;

        private InputField nameInput;
        private void Start()
        {
            messageInput = transform.FindChildByName("MessageInput").GetComponent<InputField>();
            nameInput = transform.FindChildByName("NameInput").GetComponent<InputField>();
            transform.FindChildByName("Send").GetComponent<Button>().
                onClick.AddListener(OnSendButtonClick);
            //獲取各種組建
            chatview = transform.FindChildByName("ChatView").GetComponent<ChatView>();
            UDPClientNetWorkService.Instance.MessageArrivedEventHandler 
                += OnMessageArrived;
            //註冊事件
        }
        //點擊調用發送消息的方法
        private void OnSendButtonClick()
        {
            ChatMessage msg = new ChatMessage()
            {
                Type = UDPNetWork.General,
                Content = messageInput.text,
                SenderName = nameInput.text
            };
            UDPClientNetWorkService.Instance.
                SendChatMessage(msg);
        }
        private ChatView chatview;
        private  void  OnMessageArrived(MessageArrivedEventArgs args)
        {
            //註冊方法
            //顯示消息
            ChatLine line = new ChatLine()
            {
                //事件參數對象賦值????
                Time = args.DateTime,
                Message = args.Message.Content,
                Type = ChatLineType.User,
                UserName=args.Message.SenderName
            };
            chatview.DataSource.Add(line);
            //滾動
            chatview.ScrollRect.verticalNormalizedPosition = 0;
        }
    }
}
ChatClient
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Common;
namespace  NS
{
    ///<summary>
    ///服務端顯示面板
    ///</summary>
    public class ChatServer : MonoBehaviour
    {
        private void Start()
        {
            text = transform.FindChildByName("Text").GetComponent<Text>();
            UDPServerNetWorkService.Instance.MessageArrivedEventHandler
                += OnMessageArrived;
        }
        private Text text;  
        //當服務端收到消息 顯示在文本中
        private void OnMessageArrived(MessageArrivedEventArgs obj)
        {
            Debug.Log(obj.Message.Type);
            text.text = string.Format("{0}---{1}", 
                obj.Message.Type, obj.Message.Content);
        }
    }
}
ChatServer

 工程包鏈接:  https://github.com/AnsssAS/Assect


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • eval() 將字元串當成一個表達式去執行,可以想象成一個去字元串然後執行的操作。 eval()和json.loads() 都可以將字元串轉換成對應的python數據類型,舉個字典的例子,同樣適合其他數據類型元組、列表、集合。 json一種輕量級數據交換格式,可以將json對象當作比較特殊的字元串, ...
  • C++ STL之map map介紹 C++里的map數據結構,會存儲鍵值對信息key value,通過key得到value的信息。map的key與value有一個特點就是:每個唯一的key擁有唯一對應的value,不會出現多組value與之對應。 它和其他標準模板容器不同的是,初始化它的時候要提供兩 ...
  • CMDB(資產管理資料庫) CMDB是所有運維工具的數據基礎 CMDB包含的內容 CMDB實現的三種方式 (1)Agent實現方式:Agent方式,可以將伺服器上面的Agent程式作定時任務,定時將資產信息提交到指定API錄入資料庫 其本質上就是在各個伺服器上執行subprocess.getoutp ...
  • 直接上主題: 在web.xml文件中添加如下信息: 完畢 ! ...
  • 模糊查詢用戶信息 <!-- [${}]:表示拼接SQL字元串 [${value}]:表示要拼接的是簡單類型參數。 註意: 1、如果參數為簡單類型時,${}裡面的參數名稱必須為value 2、${}會引起SQL註入,一般情況下不推薦使用。但是有些場景必須使用${},比如order by ${colna ...
  • 轉載自:https://www.cnblogs.com/yinqixin/p/5056307.html 每一個初學C#的程式猿,在剛剛碰到委托和事件的概念時,估計都是望而卻步,茫然摸不到頭腦的。百度一搜,關於概念介紹的文章大把大把的,當然也不乏深入淺出的好文章。可看完這些文章,大多數新手,估計也只是 ...
  • 優化: Calculator calculator = GetComputeObject(Operate, Number1, Number2); ...
  • C# Winform By LayeredSkin 仿小鳥壁紙 說明: 之前搜狗壁紙掛了,沒有如此好用的壁紙了就想著自己搗鼓個用,仿360小鳥壁紙開發的,界面控制項使用LayeredSkin,有興趣的可以去這CSKIN看看 功能說明: 小鳥壁紙官方資源下載線上瀏覽,搜索設置系統壁紙等 效果圖: 版本: ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...