【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议
Unity3d实战之Unity3d网络游戏实战篇(9):协议
学习书籍《Unity3d网络游戏实战》 罗培羽著 机械工业出版社
本文是作者在学习过程中遇到的认为值得记录的点,因此引用的代码等资源基本出资罗培羽老师的书籍,如有侵权请联系,必删。
一套通用的服务端框架要支持不同游戏所使用的各种协议格式。所谓协议就是通信规则,例如:如果发送端直接发送一串数值数据给接收端,接收端并不知道这一串数据到底是用来做什么的,里面的数据代表了什么信息。而协议就是解决这一问题的一套规则,一套发送端和接收端都知道的规则。在要发送的数据前添加某些标志,发送端和接收端共同规定带有这个标志的数据的用途。这样,两端就可以对接收到的数据进行解析,并根据两者共同定立的规则来分辨所接收到的数据的用途。
所有的协议都有相同的方法:解码、编码、获取协议名等等,以此为基础,我们可以编写一个协议的基类:
using System;namespace Server
{public class ProtocolBase{/// <summary>/// Decode the readBuff from start to start+length. Package readBuff as a protocol and return it./// </summary>/// <param name="readBuff">Read buff.</param>/// <param name="start">Type: int, decode begin from start.</param>/// <param name="length">Type: int, decode from begin to start+length.</param>public virtual ProtocolBase Decode(byte[] readBuff, int start, int length){return new ProtocolBase ();}/// <summary>/// Encode the protocol's content to binary array./// </summary>public virtual byte[] Encode(){return new byte[] { };}/// <summary>/// Return the protocol's name./// </summary>/// <returns>The name.</returns>public virtual string GetName(){return "";}/// <summary>/// Return the protocol's description./// </summary>/// <returns>The desc.</returns>public virtual string GetDesc(){return "";}}
}
根据需要可以定义不同类型的协议,不同类型的协议的编码解码方式不同,如字符串协议会议字符串形式解析接收到的协议,字节流协议会以字节方式解析协议。下面给出字节流代码:
using System;
using System.Linq;namespace Server
{/// <summary>/// Bytes Protocol/// Protocol Format:/// [protocollength][protocol name][data1][data2].../// protocollength: Int32 -> byte/// protocol name: byte/// data: byte/// </summary>public class ProtocolBytes : ProtocolBase{public byte[] bytes;public override ProtocolBase Decode (byte[] readBuff, int start, int length){ProtocolBytes proto = new ProtocolBytes ();proto.bytes = new byte[length];Array.Copy (readBuff, start, proto.bytes, 0, length);return (ProtocolBase)proto;}public override byte[] Encode (){return bytes;}public override string GetName (){return GetString (0);}public override string GetDesc (){if (bytes == null)return "";string str = "";for (int i = 0; i < bytes.Length; i++) {int t = (int)bytes [i];str += t.ToString () + " ";}return str;}#region Help Function#region String Operation/// <summary>/// convert the str into bytes and connect it behind the protocol./// </summary>/// <param name="str">the connected string</param>public void AddString(string str){Int32 length = str.Length;byte[] lenBytes = BitConverter.GetBytes (length);byte[] strBytes = System.Text.Encoding.UTF8.GetBytes (str);if (bytes == null)bytes = lenBytes.Concat (strBytes).ToArray ();elsebytes = bytes.Concat (lenBytes).Concat (strBytes).ToArray ();}/// <summary>/// Get a complete string from start to end./// </summary>/// <returns>string</returns>/// <param name="start">start index</param>/// <param name="end">end index</param>public string GetString(int start, ref int end){if (bytes == null)return "";if (bytes.Length < start + sizeof(Int32))return "";Int32 strLen = BitConverter.ToInt16 (bytes, start);if (bytes.Length < start + sizeof(Int32) + strLen)return "";string str = System.Text.Encoding.UTF8.GetString (bytes, start + sizeof(Int32), strLen);end = start + sizeof(Int32) + strLen;return str;}/// <summary>/// Get a complete string begin at start./// </summary>/// <returns>string</returns>/// <param name="start">start index</param>public string GetString(int start){int end = 0;return GetString (start, ref end);}#endregion#region Int32 Operation/// <summary>/// convert the Int32 into bytes and connect it behind the protocol./// </summary>/// <param name="num">Number.</param>public void AddInt32(Int32 num){byte[] numBytes = BitConverter.GetBytes (num);if (bytes == null)bytes = numBytes;elsebytes = bytes.Concat (numBytes).ToArray ();}/// <summary>/// Get a complete Int32 num from protocol's start to end./// </summary>/// <returns>Int32</returns>/// <param name="start">start index</param>/// <param name="end">end index</param>public Int32 GetInt32(int start, ref int end){if (bytes == null)return 0;if (bytes.Length < start + sizeof(Int32))return 0;end = start + sizeof(Int32);return BitConverter.ToInt32 (bytes, start);}/// <summary>/// Get a complete Int32 num from protocol's start./// </summary>/// <returns>Int32.</returns>/// <param name="start">start index</param>public Int32 GetInt(int start){int end = 0;return GetInt (start, ref end);}#endregion#region Float Operation/// <summary>/// convert the float into bytes and connect it behind the protocol./// </summary>/// <param name="num">float number</param>public void AddFloat(float num){byte[] numBytes = BitConverter.GetBytes (num);if (bytes == null)bytes = numBytes;elsebytes = bytes.Concat (numBytes).ToArray ();}/// <summary>/// Get a complete float num from protocol's start to end./// </summary>/// <returns>The float.</returns>/// <param name="start">start index</param>/// <param name="end">end index</param>public float GetFloat(int start, ref int end){if (bytes == null)return 0;if (bytes.Length < start + sizeof(float))return 0;end = start + sizeof(float);return BitConverter.ToSingle (bytes, start);}/// <summary>/// Get a complete float num from protocol's start./// </summary>/// <returns>The float.</returns>/// <param name="start">start index</param>public float GetFloat(int start){int end = 0;return GetFloat (start, ref end);}#endregion#endregion}
}
使用Help Function中的方法可以对协议进行一定的操作,如添加协议名、添加数据等。
我一开始在这里陷入了混乱,为什么添加String时需要打包string长度,而添加int和float时就不需要在数据前添加数据长度,后来发现这是因为string的长度是不确定的,而int和float的长度都是确定的,如Int32的长度为4byte,在获取Int时,BitConverter可以直接获取start位置往后4byte的数据并将它转化为Int32类型,显然string就不行,因此它需要添加数据长度信息。
在完成协议后,我们就可以使用协议进行通信了,在发送协议时记得要给在发送的数据包前加上整条协议的长度信息。
【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议相关推荐
- 【实战】Unity3d实战之Unity3d网络游戏实战篇(11):消息分发
Unity3d实战之Unity3d网络游戏实战篇(11):消息分发 学习书籍<Unity3d网络游戏实战> 罗培羽著 机械工业出版社 本文是作者在学习过程中遇到的认为值得记录的点,因此引用 ...
- 《Unity3D网络游戏实战》第7章
<Unity3D网络游戏实战>第7章 服务端架构 总体架构 模块划分 游戏流程 Json编码解码 添加协议文件 引用System.web.Extensions 修改MsgBase类 测试 ...
- 视频教程-MMOARPG地下守护神_单机版实战视频课程(上部) -Unity3D
MMOARPG地下守护神_单机版实战视频课程(上部) 二十多年的软件开发与教学经验IT技术布道者,资深软件工程师.具备深厚编程语言经验,在国内上市企业做项目经理.研发经理,熟悉企业大型软件运作管理过程 ...
- 视频教程-MMOARPG地下守护神_单机版实战视频课程(下部) -Unity3D
MMOARPG地下守护神_单机版实战视频课程(下部) 二十多年的软件开发与教学经验IT技术布道者,资深软件工程师.具备深厚编程语言经验,在国内上市企业做项目经理.研发经理,熟悉企业大型软件运作管理过程 ...
- 【Unity3D实战】方块跑酷初级开发实战(一)
[Unity3D实战]方块跑酷初级开发实战(一) 欢迎大家来到LDS的博客,今天开始我们讲解一下跑酷类游戏的基本操作,本文为原创,视频请观看[ http://www.mkcode.net/html/u ...
- Unity 3D网络游戏实战 pdf
Unity 3D网络游戏实战(全) 目录: 掌握Unity3D基本元素 1.1 简单的游戏 1.1.1在场景中创建一个立方体 1.1.2编写可以使立方体运动的程序 1.1.3测试游戏1.1.4总结1. ...
- .NET Core实战项目之CMS 第十章 设计篇-系统开发框架设计
这两天比较忙,周末也在加班,所以更新的就慢了一点,不过没关系,今天我们就进行千呼万唤的系统开发框架的设计.不知道上篇关于架构设计的文章大家有没有阅读,如果阅读后相信一定对架构设计有了更近一部的理解,如 ...
- .NET Core实战项目之CMS 第九章 设计篇-白话架构设计
前面两篇文章给大家介绍了我们实战的CMS系统的数据库设计,源码也已经上传到服务器上了.今天我们就好聊聊架构设计,在开始之前先给大家分享一下这几天我一直在听的<从零开始学架构>里面关于架构设 ...
- .NET Core实战项目之CMS 第八章 设计篇-内容管理极简设计全过程
写在前面 上一篇文章.NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程中我带着大家进行了权限部分的极简设计,也仅仅是一个基本的权限设计.不过你完全可以基于这套权限系统设计你的更 ...
最新文章
- 记录Mask RCNN调整预测网格 font大小
- linux 输出重定向_linux学习笔记(实验楼) 实验12 数据流重定向
- MariaDB 修改存储路径后启动失败问题解决
- 加密连接工具Cryptcat
- 【项目管理】敏捷原则
- ffmpeg 时间戳
- javascript Function()
- 浅谈iOS中的蓝牙技术(一) GameKit framework
- dataGridView1.DataSource多增加列,数据不进自己规定的列?
- qt web混合编程_VS2017+QT 混合编程-在VS控制台程序配置QT
- 精通Android【Android移动开发制胜宝典】
- 为什么使用梯度下降法或者梯度上升法
- java课程 数独 文库_数独教案-完整版
- GD32 MCU USB开发学习记录
- 分享五个免费图片/视频资源网站
- 时光飞逝,博客两周年啦
- php 开源项目汇总
- 后端使用SpringBoot和Jwt工具与Redis数据库+前端Vue Element Admin实现用户携带token的登录功能案例
- PPT文件解除编辑限制密码
- multithreading coding
热门文章
- 计算机图形在虚拟现实中的应用,虚拟现实环境中计算机图形场景实现方法研究...
- Javaweb图书管理系统t
- C#之CAD二次开发(10) 用户交互之选择集
- 有人说Java是世界上最好的语言,也有人说Java这几年就会没落,你怎么看呢
- 在自己的服务器上搭建git仓库服务器(本地推送到远程仓库、远程仓库推送到本地)
- 一棵高度为h的满m叉树,根节点所在的层次为第1层。若按层次自顶向下,同一层自左向右,顺序从1开始对全部结点进行编号,则结点i的第1个子结点编号j为
- 小白学 Python 数据分析(1):数据分析基础
- Welcome to the skynet wiki!
- 代码随想录Day02 | LeetCode977.有序数组的平方、LeetCode209.长度最小的子数组、LeetCode59.螺旋矩阵II
- linux光盘有iscsi安装包,linux上安装iscsi软件