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


      效果展示(尚未完善)

    UDP

    User Data Protocol 用户数据报协议

    概述

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

    数据报模式:由于不建立连接,收到的数据可能是任意主机发送的,所以接收端Read次数必须与发送端Write次数相同,每次只接收一个报文,避免多个报文合并如果报文过长多出部分会被丢弃,所以注意数据最大为1472字节

    实现步骤

    服务端                                                客户端

    获取本机终结点                                  获取本机终结点

    创建UdpClient对象                              创建UdpClient对象                                   

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

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

    ……                                                    … 

    关闭连接                                           关闭连接

    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
  • 相关阅读:
    Spring Boot SockJS应用例子
    Spring Boot+STOMP解决消息乱序问题
    Spring boot集成Websocket,前端监听心跳实现
    吐槽Windows 8,就没见过这么烂的平板操作系统
    怎样在MyEclipse上耍Chrome
    HDOJ 4876 ZCC loves cards
    IIS7.5 配置 PHP 5.3.5
    关于ANDROID模拟器的一些事
    性能測试命令字段解释
    排序算法复习
  • 原文地址:https://www.cnblogs.com/ASsss/p/10446364.html
Copyright © 2020-2023  润新知