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

转载于:https://www.cnblogs.com/ASsss/p/10457175.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
<计算机网络实验> 基于TCP的网络聊天的设计 -实验指导 一、实验目的 1.掌握通信规范的制定及实现。 2.练习较复杂的网络编程,能够把协议设计思想应用到现实应用中。 二、实验内容和要求 1.进一步熟悉VC++6编程环境; 2.利用VC++6进行较复杂的网络编程,完成网络聊天的设计及编写; 三、实验(设计)仪器设备和材料 1.计算机及操作系统:PC机,Windows; 2.网络环境:可以访问互联网; 四、 TCP/IP程序设计基础 基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序一般分为服务器端和用户端两部分。设计思路(VC6.0下): 第一部分 服务器端 一、创建服务器套接字(create)。 二、服务器套接字进行信息绑定(bind),并开始监听连接(listen)。 三、接受来自用户端的连接请求(accept)。 四、开始数据传输(send/receive)。 五、关闭套接字(closesocket)。 第二部分 客户端 一、创建客户套接字(create)。 二、与远程服务器进行连接(connect),如被接受则创建接收进程。 三、开始数据传输(send/receive)。 四、关闭套接字(closesocket)。 CSocket的编程步骤:(注意我们一定要在创建MFC程序第二步的时候选上Windows Socket选项,其中ServerSocket是服务器端用到的,ClientSocket是客户端用的。) (1)构造CSocket对象,如下例: CSocket ServerSocket; CSocket ClientSocket; (2)CSocket对象的Create函数用来创建Windows Socket,Create()函数会自行调用Bind()函数将此Socket绑定到指定的地址上面。如下例: ServerSocket.Create(823); //服务器端需要指定一个端口号,我们用823。 ClientSocket.Create(); //客户端不用指定端口号。 (3)现在已经创建完基本的Socket对象了,现在我们来启动它,对于服务器端,我们需要这个Socket不停的监听是否有来自于网络上的连接请求,如下例: ServerSocket.Listen(5);//参数5是表示我们的待处理Socket队列中最多能有几个Socket。 (4)对于客户端我们就要实行连接了,具体实现如下例: ClientSocket.Connect(CString SerAddress,Unsinged int SerPort);//其中SerAddress是服务器的IP地址,SerPort是端口号。 (5)服务器是怎么来接受这份连接的呢?它会进一步调用Accept(ReceiveSocket)来接收它,而此时服务器端还须建立一个新的CSocket对象,用它来和客户端进行交流。如下例: CSocket ReceiveSocket; ServerSocket.Accept(ReceiveSocket); (6)如果想在两个程序之间接收或发送信息,MFC也提供了相应的函数。如下例: ServerSocket.Receive(String,Buffer); //String是你要发送的字符串,Buffer是发送字符串的缓冲区大小。ServerSocket.Send(String,Butter);//String是你要接收的字符串,Buffer是接收字符串的缓冲区大小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值