Unity3D游戏开发

网络框架

2019-11-28  本文已影响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,

}

上一篇下一篇

猜你喜欢

热点阅读