网络框架

作者: 我家菇凉 | 来源:发表于2019-11-28 19:56 被阅读0次

    客户端 


    using System.Collections;

    using System.Collections.Generic;

    using UnityEngine;

    public class mManagerSocket :Singleton<mManagerSocket>

    {

        // 消息队列中的元素类型

        class MsgItem

        {

            //消息类型

            public int msgid;

            public byte[] msg;

        }

        // 代参数的委托类

        public delegate void OnMessage_CenterFunce( byte[] msg);

        // 每一个客户端给服务器的消息ID对应一个委托类,放入字典管理起来

        public Dictionary<int, OnMessage_CenterFunce> dic = new Dictionary<int, OnMessage_CenterFunce>();

        // 消息队列,用于存储从服务器接受来的包,便于主线程获取处理

        private Queue<MsgItem> all_Msgitem = new Queue<MsgItem>();

        // 注册消息处理回调

        public void OnResour_Funces(int msgid, OnMessage_CenterFunce resFunces)

        {

            //定义一个准备接受从那个字典类去除来的属性

            OnMessage_CenterFunce funce = null;

            //判断根据消息类型拿出对应的委托类

            if (dic.TryGetValue(msgid, out funce))

            {

                //注册消息回调函数

                funce += resFunces;

            }

            else

            {

                //如果没有加入到字典管理起来

                dic.Add(msgid, resFunces);

            }

        }

        /// <summary>

        /// 对队里中的数据进行发布

        /// </summary>

        /// <param name="msgid"></param>

        /// <param name="clientid"></param>

        /// <param name="msg"></param>

        public void OnMessagehandling(int msgid,byte[] msg)

        {

            //根据从队列去处的消息类型拿到集合内对应的事件类

            OnMessage_CenterFunce funce = null;

            //判断根据消息类型拿出对应的委托类

            if (dic.TryGetValue(msgid, out funce))

            {

                //事件发布

                funce(msg);

            }

        }

        // 把收到的消息压入队列

        public void All_Enqueue(int msgid, byte[] msg)

        {

            //建立一个元素对象

            MsgItem item = new MsgItem();

            //同上(消息类型)

            item.msgid = msgid;

            //把传入进来的具体消息复制到队列类中

            item.msg = msg;

            //防止多个客户端连接进来

            lock (all_Msgitem)

            {

                //把消息压入队列

                all_Msgitem.Enqueue(item);

            }

        }

        // 处理该客户端消息队列中的消息

        public void Dele_Dequeue()

        {

            //一次性处理完所有的积累消息

            while (true)

            {

                //如果消息处里完毕了,退出

                if (all_Msgitem.Count <= 0)

                {

                    return;

                }

                //处理消息出队

                MsgItem item = all_Msgitem.Dequeue();

                //调用--- 事件发布

                OnMessagehandling(item.msgid,item.msg);

            }

        }

    }





    using System.Collections;

    using System.Collections.Generic;

    using UnityEngine;

    using System.Net;

    using System.Net.Sockets;

    using System;

    using System.IO;

    public class NetClicent : Singleton<NetClicent>

    {

        // 异步通讯所用的附带数据类型

        class AscyData

        {

            // 消息ID

            public int mesid;

            // 当前写入位置

            public int pos;

            // 缓冲区

            public byte[] buff;

        }

        // 消息ID长度

        public const int MSG_ID_SIZE = sizeof(int);

        // 包头长度

        public const int HONE_SIZE = sizeof(ushort);

        public Socket mServerSocket;

        public void StartServer(string mIP, int mPort)

        {

            mServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPEndPoint IPE = new IPEndPoint(IPAddress.Parse(mIP), mPort);

            try

            {

                mServerSocket.Connect(IPE);

            }

            catch (System.Exception)

            {

              Debug.Log("连接失败");

                throw;

            }

            Debug.Log("连接服务端成功。。。");

            Start_Subpackage();

        }

        //异步读取包处

        private void Start_Subpackage()

        {

            //异步读取所有用到的属性,读取从包头加消息类型开始

            AscyData data = new AscyData()

            {

                buff = new byte[HONE_SIZE + MSG_ID_SIZE],

            };

            mServerSocket.BeginReceive(data.buff, 0, data.buff.Length, SocketFlags.None, BeginHone, data);

        }

        private void BeginHone(IAsyncResult ar)

        {

            //拿到发送过来的长度

            int len = mServerSocket.EndReceive(ar);

            //从系统中取出之前传入的参数

            AscyData data = ar.AsyncState as AscyData;

            //判断包的长度和MSGID是否都接受成功

            if (len + data.pos == data.buff.Length)

            {

                //从接受完的字节数组中取出总长度 0代表从0开始全部转换完毕

                ushort paselen = BitConverter.ToUInt16(data.buff, 0);

                //从接受完的字节数组中取出消息的ID类型 2代表从0开始只转换两个字节

                int mesid = BitConverter.ToInt32(data.buff, HONE_SIZE);

                //开启一个异步读取包体的对象存储的位置

                AscyData da = new AscyData()

                {

                    buff = new byte[paselen - MSG_ID_SIZE],

                    mesid = mesid,

                };

                mServerSocket.BeginReceive(da.buff, 0, da.buff.Length, SocketFlags.None, BeginBody, da);

            }

            else

            {

                //没有读取完则继续读取包头的剩余部分

                data.pos += len;

                //异步开始读取包体

                mServerSocket.BeginReceive(data.buff, data.pos, data.buff.Length - data.pos, SocketFlags.None, BeginHone, data);

            }

        }

        private void BeginBody(IAsyncResult ar)

        {

            //同上 --他们所拿到的数据和长度都是真实的数据

            int len = mServerSocket.EndReceive(ar);

            //获取之前开启存储数据的类的对象

            AscyData data = ar.AsyncState as AscyData;

            //判断是否读取完毕,读取完毕就放入队列

            if (len + data.pos == data.buff.Length)

            {

              mManagerSocket.Instance .All_Enqueue(data.mesid,data.buff);


                //开启读取下一个包

                Start_Subpackage();//再次进行回调

            }

            else

            {

                //把么有读取完的数据增加到有效数据的末尾

                data.pos += len;

                mServerSocket.BeginReceive(data.buff, data.pos, data.buff.Length - data.pos, SocketFlags.None, BeginHone, data);

            }

        }

        //服务返回给客户端发送消息

        public void Send(int msgid, byte[] msg)

        {

            //这个要倒IO包 他相当于一个记忆  短暂记忆的一个流  全部拿到发出去

            using (MemoryStream mm = new MemoryStream())

            {

                //拿到你要发送的总长度

                ushort length = (ushort)(msg.Length + MSG_ID_SIZE);

                //通过IO流的方式连接到MemoryStream

                BinaryWriter bw = new BinaryWriter(mm);

                //包头放置数据长度,2个字节

                bw.Write(length);

                //消息类型

                bw.Write(msgid);

                //具体数据

                bw.Write(msg);

                //两种写法  这种是全部发送 也没问题

                // mServerSocket.Send(mm.GetBuffer());

                //返回给客户端消息处,参数一全部的数据包,参数二发送的长度(要加上包头的长度)

                mServerSocket.Send(mm.GetBuffer(), length + HONE_SIZE, SocketFlags.None);

            }

        }

    }





    using System;

    using System.Collections;

    using System.Collections.Generic;

    using UnityEngine;

    using UnityEngine.UI;

    using Google.Protobuf;

    using MyUser;

    //意思是 S——服务端  2——TO C --客户端

    public enum S2C

    {

        TankLoginResult = 0,

        Generate_playerlist = 1,

        Anaphase_Player = 2,

        WantMove = 3,

    }

    /// <summary>

    /// 所有客户端给服务器的消息id类型

    /// </summary>

    //客户端发送给服务端

    public enum C2S

    {

        TankLoginResult = 0,

        Generate_playerlist = 1,

        Anaphase_Player = 2,

        WantMove = 3,

    }

    相关文章

      网友评论

        本文标题:网络框架

        本文链接:https://www.haomeiwen.com/subject/qykiwctx.html