UDP实现一个简易的聊天室 (Unity&&C#完成)

  效果展现(还没有完善)
ide

UDP

User Data Protocol 用户数据报协议工具

概述

UDP不链接的数据报模式。即传输数据以前源端和终端不创建链接使用尽最大努力交付原则,即不保证可靠交付ui

数据报模式:因为不创建链接,收到的数据多是任意主机发送的,因此接收端Read次数必须与发送端Write次数相同,每次只接收一个报文,避免多个报文合并若是报文过长多出部分会被丢弃,因此注意数据最大为1472字节this

 

实现步骤

 

服务端                                                客户端spa

获取本机终结点                                  获取本机终结点线程

建立UdpClient对象                              建立UdpClient对象                                   code

接收任意终结点消息                             接收任意终结点消息orm

向客户端发送消息                               向服务端发送消息server

……                                                    … 对象

关闭链接                                           关闭链接

 

ChatUDPClientTest
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading; using System.Net; using System.Net.Sockets; using System.Text; using Common; using UIWidgetsSamples; using System; /// <summary>
/// 服务端 /// </summary>
public class ChatUDPServerTest : MonoBehaviour { public string serverIP; //IP地址
    public int serverPort; //端口 //1.建立Scoket对象 IP Port
    private Thread thread; private UdpClient udpSeivic; public void Start() { chatView = transform.FindChildByName("ChatView"). GetComponent<ChatView>(); //给端口和IP //构建终结点 IP和一个端口
        IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(serverIP), serverPort); udpSeivic = new UdpClient(localEP); thread = new Thread(ReceiveMessage); thread.Start(); } /// <summary>
    /// 接收消息 /// </summary>
    private void ReceiveMessage() { while (true) { IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0); //建立任意终结点 //ref
            byte[] date = udpSeivic.Receive(ref remote); //Receive接收消息 若是没有收到消息 线程阻塞 放在线程中
            string msg = Encoding.UTF8.GetString(date); //获取的客户都安信息
            Debug.Log(remote.Address + "===" + remote.Port); //若是接收客户端的消息,会把任意终结点修改成客户端的终结点
            ThreadCrossHelper.Instance.ExecuteOnMainThread(() => { ShowMessage(msg); }); } } private ChatView chatView; /// <summary>
    /// 显示消息 /// </summary>
    /// <param name="msg"></param>
    public void ShowMessage(string msg) { chatView.DataSource.Add(new ChatLine() { UserName = "AnnnS", Message = msg, Time = DateTime.Now, Type = ChatLineType.User, }); } private void OnApplicationQuit() { udpSeivic.Close(); thread.Abort(); } }
ChatUDPServerTest

脚本引用的工具箱

  1. MonoSingleton (泛型单例)
  2. ThreadCrossHelper (为子线程提供,能够在主线程中执行的方法)
  3. TransformHelper(根据名称查找后代元素)
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Common { /// <summary>
    /// 
    /// </summary>
    public class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T> { //public static T Instance //{ // get; // private set; //} //private void Awake() //{ // Instance = this as T; //} //按需加载
        private static T instance; public static T Instance { get { if (instance == null) { //在场景中查找对象
                    instance = FindObjectOfType<T>(); if (instance == null) { //建立游戏对象 附加 脚本对象
                        new GameObject("Singleton of " + typeof(T)).AddComponent<T>();//当即执行Awake
 } else { instance.Initialized(); } } return instance; } } protected virtual void Initialized() { } [Tooltip("是否须要跨场景不销毁")] public bool isDontDestroy = true; //若是管理类自行附加到物体中 //在Awake中为instance赋值 
        protected void Awake() { if (isDontDestroy) { DontDestroyOnLoad(gameObject); } if (instance == null) { instance = this as T; instance.Initialized(); } } } }
MonoSingleton
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Common { /// <summary>
    /// 
    /// </summary>
    public class ThreadCrossHelper : MonoSingleton<ThreadCrossHelper> { /// <summary>
        /// 延迟项 /// </summary> 
        class DelayedItem { public Action CurrentAction { get; set; } public DateTime Time { get; set; } } private List<DelayedItem> actionList; //private List<Action> actionList; //private List<float> timeList;

        protected override void Initialized() { base.Initialized(); actionList = new List<DelayedItem>(); } private void Update() { for (int i = actionList.Count - 1; i >= 0; i--) { //到时间
                if (actionList[i].Time <= DateTime.Now) { lock (actionList) { actionList[i].CurrentAction();//执行
                        actionList.RemoveAt(i);//从列表中移除 
 } } } } /// <summary>
        /// 为子线程提供,能够在主线程中执行的方法 /// </summary>
        /// <param name="action"></param>
        /// <param name="dealy"></param>
        public void ExecuteOnMainThread(Action action, float dealy = 0) { DelayedItem item = new DelayedItem() { CurrentAction = action, //Time = Time.time + dealy
                Time = DateTime.Now.AddSeconds(dealy) }; lock (actionList) { actionList.Add(item); } } } }
ThreadCrossHelper
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Common { /// <summary>
    /// 变换组件助手类 /// </summary>
    public static  class TransformHelper { /// <summary>
        /// 未知层级,根据名称查找后代元素 /// </summary>
        /// <param name="currentTF"></param>
        /// <param name="childName"></param>
        /// <returns></returns>
        public static Transform FindChildByName(this Transform currentTF, string childName) { Transform childTF = currentTF.Find(childName); if (childTF != null) return childTF; //将问题推迟给子物体
            for (int i = 0; i < currentTF.childCount; i++) { //在方法体内部,又遇到了相同的问题,因此须要调用自身。
                childTF = FindChildByName(currentTF.GetChild(i), childName); if (childTF != null) return childTF; } return null; } } }
TransformHelper
相关文章
相关标签/搜索