当前位置: 移动技术网 > IT编程>开发语言>.net > UDP实现一个简易的聊天室(多个主机连接终端) 已完善

UDP实现一个简易的聊天室(多个主机连接终端) 已完善

2019年03月02日  | 移动技术网IT编程  | 我要评论

线人 下载,万家乐电磁炉维修,河北卫视logo

 效果展示 

 

 

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网