2019-9-15

Unity中的网络框架

此框架使主要负责客户端和服务端的连接以及数据交换具体实现逻辑根据实际项目进行编写,注册到委托中即可

/// <summary>

    /// 通用socket端

    /// </summary>

    public class SocketObject

    {

        public Socket socket;//套接字

        public byte[] recvBuf;//接收缓冲区

        public byte[] sendBuf;//发送缓冲区

        public Queue<NetMsgObj> recvQueue;//接收队列

        public Queue<NetMsgObj> sendQueue;//发送队列

        public IPEndPoint point;//终端

        public string IP;//IP

        public short Port;//端口

        public static SocketObject Regist(string ip,short port)

        {

            SocketObject temp = new SocketObject();

            temp.IP = ip;

            temp.Port = port;

            temp.point = new IPEndPoint(IPAddress.Parse(ip),port);

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

            temp.recvBuf = new byte[4096];

            temp.sendBuf = new byte[4096];

            temp.recvQueue = new Queue<NetMsgObj>();

            temp.sendQueue = new Queue<NetMsgObj>();

            return temp;

        }

        /// <summary>

        /// 设置Socket

        /// </summary>

        /// <param name="s"></param>

        public void SetSocket(Socket s)

        {

            socket = s;

        }

        /// <summary>

        /// 进入接收队列方法

        /// </summary>

        /// <param name="nmo"></param>

        public void EnRecvQueue(NetMsgObj nmo)

        {

            recvQueue.Enqueue(nmo);

        }

        /// <summary>

        /// 进入发送队列方法 

        /// </summary>

        /// <param name="nmo"></param>

        public void EnSendQueue(NetMsgObj nmo)

        {

            sendQueue.Enqueue(nmo);

        }

    }


/// <summary>

    /// 消息传递类(协议)此协议根据实际需求进行更改,此处只做示范

    /// </summary>

    public class NetMsgObj

    {

        public int len;//长度

        public MsgCode code;

        public byte[] data;

        /// <summary>

        /// 获取消息号

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public static MsgCode  GetCode(byte[] data)

        {

            byte[] temp = new byte[2];

            temp[0] = data[4];

            temp[1] = data[5];

            return (MsgCode)BitConverter.ToInt16(temp,0);

        }

        /// <summary>

        /// 序列化

        /// </summary>

        /// <param name="head"></param>

        /// <param name="body"></param>

        /// <returns></returns>

        public static byte[] Package(MsgCode code,byte[] body)

        {

            byte[] temp = new byte[6 + body.Length];

            byte[] bs = BitConverter.GetBytes((short)code);

            byte[] length = BitConverter.GetBytes(temp.Length);

            Array.Copy(length, 0, temp, 0, 4);

            Array.Copy(bs,0,temp,4,2);

            Array.Copy(body,0,temp,6,body.Length);

            return temp;

        }

        /// <summary>

        /// 反序列化

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public static NetMsgObj GetNMO(byte[] data)

        {

            NetMsgObj temp = new NetMsgObj();

            temp.len = GetHead(data);

            temp.code = GetCode(data);

            byte[] body = new byte[data.Length - 6];

            Array.Copy(data, 6, body, 0, body.Length);

            temp.data = body;

            return temp;

        }

        /// <summary>

        /// 打包数据

        /// </summary>

        /// <returns></returns>

        public byte[] Package()

        {

            byte[] temp = new byte[6 + data.Length];

            byte[] length = BitConverter.GetBytes(temp.Length);

            byte[] codes = BitConverter.GetBytes((short)code);

            Array.Copy(length, 0, temp, 0, 4);

            Array.Copy(codes, 0, temp, 4, 2);

            Array.Copy(data, 0, temp, 6, data.Length);

            return temp;

        }

        /// <summary>

        /// 获取头(长度)

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public static int GetHead(byte[] data)

        {

            byte[] head = new byte[4];

            for (int i = 0; i < 4; i++)

            {

                head[i] = data[i];

            }

            return BitConverter.ToInt32(head,0);

        }

    }


public delegate void Handle(NetMsgObj nmo);

//客户端类 此类可以在服务器承载连接上的客户端,也可以直接当做客户端使用

    public class Client

    {

        public string clientID;

        public event Handle Handler;


        public int content;//剩余容量

        public int read = 0;//已用容量

        public SocketObject socketObject;

        public void AddListener(Handle h)

        {

            Handler += h;

        }

        /// <summary>

        /// 初始化客户端

        /// </summary>

        /// <param name="ip"></param>

        /// <param name="port"></param>

        public void Init(string ip = "127.0.0.1", short port = 4396)

        {

            socketObject = SocketObject.Regist(ip, port);

            content = socketObject.recvBuf.Length;


        }

        /// <summary>

        /// 连接服务器

        /// </summary>

        public void ConnectServer()

        {

            socketObject.socket.BeginConnect(socketObject.point, AsyncConnectCallBack, socketObject);

        }

        /// <summary>

        /// 连接回调

        /// </summary>

        /// <param name="ar"></param>

        private void AsyncConnectCallBack(IAsyncResult ar)

        {

            SocketObject so = (SocketObject)ar.AsyncState;

            so.socket.EndConnect(ar);

            Debug.Log("连接成功");

            if (so.socket.Connected)

                so.socket.BeginReceive(so.recvBuf, 0, so.recvBuf.Length, SocketFlags.None, AsyncRecvCallBack, so);

        }

        /// <summary>

        /// 服务器调用接收

        /// </summary>

        public void RecvProcess()

        {

            if (socketObject.socket.Connected)

                socketObject.socket.BeginReceive(socketObject.recvBuf, read, content, SocketFlags.None, AsyncRecvCallBack, socketObject);

        }

        /// <summary>

        /// 接收回调

        /// </summary>

        /// <param name="ar"></param>

        private void AsyncRecvCallBack(IAsyncResult ar)

        {

            SocketObject so = (SocketObject)ar.AsyncState;

            int len = so.socket.EndReceive(ar);



            read = len;

            while (true)

            {

                if (read < 6)

                    break;

                int plen = BitConverter.ToInt32(socketObject.recvBuf,0);

                if (read < plen)

                    break;

                byte[] temp = new byte[plen];

                Array.Copy(socketObject.recvBuf,0,temp,0,plen);

                NetMsgObj nmo = NetMsgObj.GetNMO(temp);

                socketObject.recvQueue.Enqueue(nmo);

                Array.Copy(socketObject.recvBuf,plen,socketObject.recvBuf,0,read-plen);

                read -= plen;

                content = so.recvBuf.Length - read;

            }

            if (so.socket.Connected)

                so.socket.BeginReceive(so.recvBuf, read, content, SocketFlags.None, AsyncRecvCallBack, so);

        }

        /// <summary>

        /// 真实接收

        /// </summary>

        public void UpdateRecvMsg()

        {

            while (socketObject.recvQueue.Count > 0)

            {

                NetMsgObj temp = socketObject.recvQueue.Dequeue();

                Handler?.Invoke(temp);

            }

        }

        /// <summary>

        /// 真实发送

        /// </summary>

        public void UpdateSendMsg()

        {

            while (socketObject.sendQueue.Count > 0)

            {

                NetMsgObj temp = socketObject.sendQueue.Dequeue();

                byte[] data = temp.Package();

                socketObject.socket.BeginSend(data, 0, data.Length, SocketFlags.None, AsyncSendCallBack, socketObject);

            }

        }

        /// <summary>

        /// 发送回调

        /// </summary>

        /// <param name="ar"></param>

        private void AsyncSendCallBack(IAsyncResult ar)

        {

            SocketObject so = (SocketObject)ar.AsyncState;

            int len = so.socket.EndSend(ar);

            if (len > 0)

            {

                Debug.Log("发送成功");

            }

        }

        /// <summary>

        /// 虚假发送

        /// </summary>

        /// <param name="code"></param>

        /// <param name="data"></param>

        public void SendMsg(MsgCode code, byte[] data)

        {

            NetMsgObj temp = new NetMsgObj();

            temp.code = code;

            temp.data = data;

            temp.len = 6 + data.Length;

            socketObject.EnSendQueue(temp);

        }

        public byte[] Zhanbao()

        {

            byte[] sum = new byte[0];

            if (socketObject.recvQueue.Count > 0)

            {

                while (socketObject.recvQueue.Count > 0)

                {

                    NetMsgObj nmo = socketObject.recvQueue.Dequeue();

                    sum = Append(sum, NetMsgObj.Package(nmo.code, nmo.data));

                }

            }

            else

            {

                Location l = new Location();

                l.clientID = clientID;

                l.x = 0;

                l.z = 0;

                string str = JsonUtility.ToJson(l);

                byte[] data = NetMsgObj.Package(MsgCode.MOVE, Encoding.UTF8.GetBytes(str));

                sum = Append(sum, data);

            }

            return sum;

        }

        public byte[] Append(byte[] src, byte[] data)

        {

            byte[] temp = new byte[src.Length + data.Length];

            Array.Copy(src, 0, temp, 0, src.Length);

            Array.Copy(data, 0, temp, src.Length, data.Length);

            return temp;

        }

        /// <summary>

        /// 服务器调用发送

        /// </summary>

        public void SendProcess(byte[] data)

        {

            socketObject.socket.BeginSend(data, 0, data.Length, SocketFlags.None, AsyncSendCallBack, socketObject);

        }


    }

//这是处理的消息类型枚举,根据需求添加

public enum MsgCode

    {

        OPEN,

        CLOSE,

        CLOSEALL,

        LOGIN,

        MOVE,

        OTHER,

        HEART,

        PONG,

    }

//服务器类,此类负责服务器的数据接收,以及接收连接上的客户端

public class Server

    {

        static int index = 1000;

        SocketObject socketObject;

        public List<Client> users = new List<Client>();

        Dictionary<string, Client> usersID = new Dictionary<string, Client>();//userID字典

        public void Init(string ip = "127.0.0.1", short port = 4396)

        {

            socketObject = SocketObject.Regist(ip, port);

        }

        /// <summary>

        /// 开启服务器

        /// </summary>

        public void StartServer(int number = 20)

        {

            socketObject.socket.Bind(socketObject.point);

            socketObject.socket.Listen(number);

            socketObject.socket.BeginAccept(AsyncAcceptCallBack, socketObject);

        }

        /// <summary>

        /// 接受回调

        /// </summary>

        /// <param name="ar"></param>

        private void AsyncAcceptCallBack(IAsyncResult ar)

        {

            SocketObject so = (SocketObject)ar.AsyncState;

            Socket s = so.socket.EndAccept(ar);

            Client c = new Client();

            c.Init();

            c.socketObject.SetSocket(s);

            string id = "Player" + index++;

            byte[] data = NetMsgObj.Package(MsgCode.LOGIN, Encoding.UTF8.GetBytes(id));

            byte[] data2 = NetMsgObj.Package(MsgCode.OTHER, Encoding.UTF8.GetBytes(id));

            foreach (var item in users)

            {

                item.SendProcess(data2);

            }

            users.Add(c);

            usersID.Add(id, c);

            c.SendProcess(data);

            foreach (var item in usersID.Keys)

            {

                byte[] data3 = NetMsgObj.Package(MsgCode.OTHER, Encoding.UTF8.GetBytes(item));

                c.SendProcess(data3);

            }

            c.RecvProcess();

            socketObject.socket.BeginAccept(AsyncAcceptCallBack, socketObject);

        }

        public void UpdateRecv()

        {

            if (users.Count > 0)

            {

                foreach (var item in users)

                {

                    item.UpdateRecvMsg();

                }

            }

        }

        public void UpdateSend()

        {

            if (users.Count > 0)

            {

                foreach (var item in users)

                {

                    item.UpdateSendMsg();

                }

            }

        }

    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,639评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,093评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,079评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,329评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,343评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,047评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,645评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,565评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,201评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,338评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,014评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,701评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,194评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,685评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,345评论 2 358

推荐阅读更多精彩内容