zoukankan      html  css  js  c++  java
  • UDP实现一个简易的聊天室(多个主机连接终端) 已完善

     效果展示 

    网络编程 --使用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

  • 相关阅读:
    TIF转JPG
    跨线程取出控件的值的写法(不是跨线程赋予控件值)
    oracle根据正则表达式查找对应的字段
    oracle数据库连接字符串
    access检测表没有的字段,添加之
    解决 Unable to load DLL 'OraOps9.dll': 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)
    oracle关键字使用
    to_number,Extract oracle的关键字
    OracleCommand.CommandText 无效
    调用带参数的线程两种方法
  • 原文地址:https://www.cnblogs.com/ASsss/p/10457175.html
Copyright © 2011-2022 走看看