设计思想是把协议号和协议类型分别存储起来,当我们向服务端发送协议的时候,会自动根据协议类型加上协议号,并用protobuf序列化后发给服务端,客户端收到服务端发回来的协议后,会根据协议号,用protobuf根按协议类型自动反序列化成相应的对象,并调用相应的回调方法。

首先到https://github.com/mgravell/protobuf-net下载protobuf-net源码,把protobuf-net这个目录拷到Unity工程里,

我的工程目录如下

在Unity的Assest目录下新建一个smcs.rsp文件,里面填入-unsafe,重启Uniyt就可以了,如果使用VS的话,最好设置工程允许不安全代码,不然用VS调试的时候会报错

下面是主要的代码:

ProtoDic.cs 这个是存储协议号和协议类型的文件,这个主要是用代码自动生成,最好不要手动去更改

using ServerMessage;
using System;
using System.Collections.Generic;namespace Proto
{public class ProtoDic{private static List<int> _protoId = new List<int>{1001,1002,1003};private static List<Type>_protoType = new List<Type>{typeof(SignUpResponse),typeof(TocChat),typeof(TosChat),};public static Type GetProtoTypeByProtoId(int protoId){int index = _protoId.IndexOf(protoId);return _protoType[index];}public static int GetProtoIdByProtoType(Type type){int index = _protoType.IndexOf(type);return _protoId[index];}public static bool ContainProtoId(int protoId){if(_protoId.Contains(protoId)){return true;}return false;}public static bool ContainProtoType(Type type){if(_protoType.Contains(type)){return true;}return false;}}
}

SocketClient.cs 这个是客户端的socket文件

using UnityEngine;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;
using Net;public enum DisType
{Exception,Disconnect,
}public class SocketClient
{private TcpClient client = null;private NetworkStream outStream = null;private MemoryStream memStream;private BinaryReader reader;private const int MAX_READ = 8192;private byte[] byteBuffer = new byte[MAX_READ];// Use this for initializationpublic SocketClient(){}/// <summary>/// 注册代理/// </summary>public void OnRegister(){memStream = new MemoryStream();reader = new BinaryReader(memStream);}/// <summary>/// 移除代理/// </summary>public void OnRemove(){this.Close();reader.Close();memStream.Close();}/// <summary>/// 连接服务器/// </summary>void ConnectServer(string host, int port){client = null;client = new TcpClient();client.SendTimeout = 1000;client.ReceiveTimeout = 1000;client.NoDelay = true;try{client.BeginConnect(host, port, new AsyncCallback(OnConnect), null);}catch (Exception e){Close();Debug.LogError(e.Message);}}/// <summary>/// 连接上服务器/// </summary>void OnConnect(IAsyncResult asr){outStream = client.GetStream();client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);NetManager.Instance.OnConnect();}/// <summary>/// 写数据/// </summary>void WriteMessage(byte[] message){MemoryStream ms = null;using (ms = new MemoryStream()){ms.Position = 0;BinaryWriter writer = new BinaryWriter(ms);ushort msglen = (ushort)message.Length;writer.Write(msglen);writer.Write(message);writer.Flush();if (client != null && client.Connected){byte[] payload = ms.ToArray();outStream.BeginWrite(payload, 0, payload.Length, new AsyncCallback(OnWrite), null);}else{Debug.LogError("client.connected----->>false");}}}/// <summary>/// 读取消息/// </summary>void OnRead(IAsyncResult asr){int bytesRead = 0;try{lock (client.GetStream()){         //读取字节流到缓冲区bytesRead = client.GetStream().EndRead(asr);}if (bytesRead < 1){                //包尺寸有问题,断线处理OnDisconnected(DisType.Disconnect, "bytesRead < 1");return;}OnReceive(byteBuffer, bytesRead);   //分析数据包内容,抛给逻辑层lock (client.GetStream()){         //分析完,再次监听服务器发过来的新消息Array.Clear(byteBuffer, 0, byteBuffer.Length);   //清空数组client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);}}catch (Exception ex){//PrintBytes();OnDisconnected(DisType.Exception, ex.Message);}}/// <summary>/// 丢失链接/// </summary>void OnDisconnected(DisType dis, string msg){Close();   //关掉客户端链接NetManager.Instance.OnDisConnect();}/// <summary>/// 打印字节/// </summary>/// <param name="bytes"></param>void PrintBytes(){string returnStr = string.Empty;for (int i = 0; i < byteBuffer.Length; i++){returnStr += byteBuffer[i].ToString("X2");}Debug.LogError(returnStr);}/// <summary>/// 向链接写入数据流/// </summary>void OnWrite(IAsyncResult r){try{outStream.EndWrite(r);}catch (Exception ex){Debug.LogError("OnWrite--->>>" + ex.Message);}}/// <summary>/// 接收到消息/// </summary>void OnReceive(byte[] bytes, int length){memStream.Seek(0, SeekOrigin.End);memStream.Write(bytes, 0, length);//Reset to beginningmemStream.Seek(0, SeekOrigin.Begin);while (RemainingBytes() > 2){ushort messageLen = reader.ReadUInt16();if (RemainingBytes() >= messageLen){MemoryStream ms = new MemoryStream();BinaryWriter writer = new BinaryWriter(ms);writer.Write(reader.ReadBytes(messageLen));ms.Seek(0, SeekOrigin.Begin);OnReceivedMessage(ms);}else{memStream.Position = memStream.Position - 2;break;}}byte[] leftover = reader.ReadBytes((int)RemainingBytes());memStream.SetLength(0);    memStream.Write(leftover, 0, leftover.Length);}/// <summary>/// 剩余的字节/// </summary>private long RemainingBytes(){return memStream.Length - memStream.Position;}/// <summary>/// 接收到消息/// </summary>/// <param name="ms"></param>void OnReceivedMessage(MemoryStream ms){BinaryReader r = new BinaryReader(ms);byte[] message = r.ReadBytes((int)(ms.Length - ms.Position));        ByteBuffer buffer = new ByteBuffer(message);int mainId = buffer.ReadShort();NetManager.Instance.DispatchProto(mainId, buffer);}/// <summary>/// 会话发送/// </summary>void SessionSend(byte[] bytes){WriteMessage(bytes);}/// <summary>/// 关闭链接/// </summary>public void Close(){if (client != null){if (client.Connected) client.Close();client = null;}}/// <summary>/// 发送连接请求/// </summary>public void SendConnect(){ConnectServer(AppConst.SocketAddress, AppConst.SocketPort);}/// <summary>/// 发送消息/// </summary>public void SendMessage(ByteBuffer buffer){SessionSend(buffer.ToBytes());buffer.Close();}
}

NetManager.cs 这个是网络功能的管理文件

using UnityEngine;
using System.Collections;
using Util;
using System.Collections.Generic;
using System;
using Proto;
using System.IO;namespace Net
{public class NetManager : SingletonMonoBehaviour<NetManager>{private Dictionary<Type, TocHandler> _handlerDic;private SocketClient _socketClient;SocketClient socketClient{get{if (_socketClient == null){_socketClient = new SocketClient();}return _socketClient;}}void Start(){Init();}public void Init(){_handlerDic = new Dictionary<Type, TocHandler>();socketClient.OnRegister();}/// <summary>/// 发送链接请求/// </summary>public void SendConnect(){socketClient.SendConnect();}/// <summary>/// 关闭网络/// </summary>public void OnRemove(){socketClient.OnRemove();}/// <summary>/// 发送SOCKET消息/// </summary>public void SendMessage(ByteBuffer buffer){socketClient.SendMessage(buffer);}/// <summary>/// 发送SOCKET消息/// </summary>public void SendMessage(object obj){if (!ProtoDic.ContainProtoType(obj.GetType())){Debug.LogError("不存协议类型");return;}ByteBuffer buff = new ByteBuffer();int protoId = ProtoDic.GetProtoIdByProtoType(obj.GetType());buff.WriteShort((ushort)protoId);MemoryStream ms = new MemoryStream();ProtoBuf.Serializer.Serialize(ms, obj);byte[] result = ms.ToArray();buff.WriteBytes(result);SendMessage(buff);}/// <summary>/// 连接 /// </summary>public void OnConnect(){Debug.Log("======连接========");}/// <summary>/// 断开连接/// </summary>public void OnDisConnect(){Debug.Log("======断开连接========");}/// <summary>/// 派发协议/// </summary>/// <param name="protoId"></param>/// <param name="buff"></param>public void DispatchProto(int protoId, ByteBuffer buff){if(!ProtoDic.ContainProtoId(protoId)){Debug.LogError("未知协议号");return;}Type protoType = ProtoDic.GetProtoTypeByProtoId(protoId);object toc = ProtoBuf.Serializer.Deserialize(protoType, new MemoryStream(buff.ReadBytes()));sEvents.Enqueue(new KeyValuePair<Type, object>(protoType, toc));}static Queue<KeyValuePair<Type, object>> sEvents = new Queue<KeyValuePair<Type, object>>();/// <summary>/// 交给Command,这里不想关心发给谁。/// </summary>void Update(){if (sEvents.Count > 0){while (sEvents.Count > 0){KeyValuePair<Type, object> _event = sEvents.Dequeue();if (_handlerDic.ContainsKey(_event.Key)){_handlerDic[_event.Key](_event.Value);}}}}public void AddHandler(Type type, TocHandler handler){if (_handlerDic.ContainsKey(type)){_handlerDic[type] += handler;}else{_handlerDic.Add(type, handler);}}}}

最后附上一个简单的测试工程:https://github.com/caolaoyao/Chat

把工程下载下来,用Unity 5.x把开main入口就可以看到效果了

Unity使用protobuf-net实现的网络框架相关推荐

  1. 使用Unity网络框架快速开发多人联网游戏(1)

    Net网络框架基于Socket网络库扩展而成的一款强大的多人在线网络游戏插件(框架),那么下面我就带领大家来学习一个这款网络插件(框架)的开发过程. 首先,你的安装unity,  只要unity支持. ...

  2. Unity+ET6.0网络框架的网络开发基础理论

    网络编程理论基础 文章目录 网络编程理论基础 主机间通信概述 Socket通信模型 游戏服务器架构的演变过程 用户登录逻辑详解 ET6.0框架下登录源码解释 主机间通信概述 ip地址和端口号 ​ 生活 ...

  3. nohttp网络框架

    作者的博客地址:https://github.com/yanzhenjie Android Http 网络请求框架,封装于 NoHttp. Android实现Http标准协议框架,支持多种缓存模式,底 ...

  4. Android网络框架Volley的快速使用

    一.基本使用 之前做Android开发都是使用学长自己封装好的网络请求框架,第三方网络框架也很多,网上搜索了一下,大多数人推荐使用 android-async-http okhttp Volley 其 ...

  5. 网络框架 - 收藏集 - 掘金

    浅谈 Retrofit 封装 - 让框架更加简洁易用 - Android - 掘金 尊重他人的劳动成果,转载请标明出处:http://blog.csdn.net/gengqiqu..., 本文出自:[ ...

  6. Android网络框架-OkHttp3.0总结

    一.概述 OkHttp是Square公司开发的一款服务于android的一个网络框架,主要包含: 一般的get请求 一般的post请求 基于Http的文件上传 文件下载 加载图片 支持请求回调,直接返 ...

  7. Android之对Volley网络框架的一些理解

    转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/50888340 本文出自:[顾林海的博客] ##前言 Volley这个网 ...

  8. 【OkHttp】OkHttp 源码分析 ( 网络框架封装 | OkHttp 4 迁移 | OkHttp 建造者模式 )

    OkHttp 系列文章目录 [OkHttp]OkHttp 简介 ( OkHttp 框架特性 | Http 版本简介 ) [OkHttp]Android 项目导入 OkHttp ( 配置依赖 | 配置 ...

  9. 云炬Android开发笔记 5-7网络框架优化与完善

    4.网络框架优化与完善 4.1[支持原始数据的post请求] 4.2[支持原始数据的putRaw] 4.3[增加UPLOAD上传方法] [会存在文件的传递]

  10. 云炬Android开发笔记 5-1,2网络框架接口创建

    1.网络框架接口创建 1.1 使用的是第三方的框架 [第三方框架]Retrofit,封装一个通用的框架,可以使用RxJava和RxAndroid进行封装,比较难,这里不做讲解: 1.2 restful ...

最新文章

  1. SAP PM 初级系列5 - 工作中心相关的配置
  2. 前端模块化,AMD与CMD的区别
  3. Spring Boot内容概要
  4. Java BigDecimal plus()方法与示例
  5. uva 1220——Party at Hali-Bula
  6. 每日一题(32)—— 联合体大小
  7. 模板题——数位DP、状态压缩、记忆化搜索
  8. 爬虫python编程与cvi编程_编程小白如何写爬虫程序
  9. 最新VS2012破解 序列号,vs2012旗舰版密钥序列号【收藏】
  10. 高数__已知2个平面方程, 求这2个平面的夹角
  11. matlab命令窗口作用是什么,matlab的命令窗口的作用是什么
  12. 如何实现罗克韦尔PLC AB1756的远程监控数据采集?
  13. 【案例二】小明都可以买什么
  14. 《世界棒球》:黑人联盟
  15. C#界面程序设计——04导入并修改word文件
  16. 介绍理想工作计算机 英语作文,理想工作的英语作文7篇
  17. 软件工程专业大学生的一年半 | 2022年度总结
  18. Quectel EC20 R2.1 AT指令集(基础部分)
  19. 华为OD面试——机试算法
  20. while中的continue用法,getchar及putchar使用方法

热门文章

  1. 5、Python学习笔记第5课:数据类型,运算符
  2. C# 调用微软自带SpeechSDK 实现文字转语音
  3. 2016年下半年总结(连载)!
  4. 嵌入式开发有年龄限制吗_嵌入式硬件工程师和软件工程师都有35岁的限制吗,有前辈能讲下吗?...
  5. H5新增video标签的常用属性
  6. iPhone计算机没有删除键,iphone备份相片没删除键怎么用电脑删除
  7. splatter包安装总结
  8. 静态分析工具PMD使用说明
  9. TexStudio 快捷键 ctrl+R 查找替换
  10. #内存泄露# linux常用内存相关命令