http://www.oschina.net/code/snippet_42170_37516

C#、Unity基于字节的网络通信中字节码解析类,类似java中的ByteBuffer,不过这个实现是参考的netty4中的ByteBuf类。

因为网络通道中是高字节序列,所以本类没有考虑低字节序列。

已在项目中使用,与java通信没问题

using System;

public class ByteBuffer
{
//字节缓存区
private byte[] buf;
//读取索引
private int readIndex = 0;
//写入索引
private int writeIndex = 0;
//读取索引标记
private int markReadIndex = 0;
//写入索引标记
private int markWirteIndex = 0;
//缓存区字节数组的长度
private int capacity; /**
* 构造方法
*/
private ByteBuffer(int capacity)
{
buf = new byte[capacity];
this.capacity = capacity;
} /**
* 构造方法
*/
private ByteBuffer(byte[] bytes)
{
buf = bytes;
this.capacity = bytes.Length;
} /**
* 构建一个capacity长度的字节缓存区ByteBuffer对象
*/
public static ByteBuffer Allocate(int capacity)
{
return new ByteBuffer(capacity);
} /**
* 构建一个以bytes为字节缓存区的ByteBuffer对象,一般不推荐使用
*/
public static ByteBuffer Allocate(byte[] bytes)
{
return new ByteBuffer(bytes);
} /**
* 根据length长度,确定大于此leng的最近的2次方数,如length=7,则返回值为8
*/
private int FixLength(int length)
{
int n = 2;
int b = 2;
while( b < length) {
b = 2 << n;
n++;
}
return b;
} /**
* 翻转字节数组,如果本地字节序列为低字节序列,则进行翻转以转换为高字节序列
*/
private byte[] flip(byte[] bytes)
{
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
return bytes;
} /**
* 确定内部字节缓存数组的大小
*/
private int FixSizeAndReset(int currLen, int futureLen)
{
if (futureLen > currLen)
{
//以原大小的2次方数的两倍确定内部字节缓存区大小
int size = FixLength(currLen) * 2;
if (futureLen > size)
{
//以将来的大小的2次方的两倍确定内部字节缓存区大小
size = FixLength(futureLen) * 2;
}
byte[] newbuf = new byte[size];
Array.Copy(buf, 0, newbuf, 0, currLen);
buf = newbuf;
capacity = newbuf.Length;
}
return futureLen;
} /**
* 将bytes字节数组从startIndex开始的length字节写入到此缓存区
*/
public void WriteBytes(byte[] bytes, int startIndex, int length)
{
lock (this)
{
int offset = length - startIndex;
if (offset <= 0) return;
int total = offset + writeIndex;
int len = buf.Length;
FixSizeAndReset(len, total);
for (int i = writeIndex, j = startIndex; i < total; i++, j++)
{
buf[i] = bytes[j];
}
writeIndex = total;
}
} /**
* 将字节数组中从0到length的元素写入缓存区
*/
public void WriteBytes(byte[] bytes, int length)
{
WriteBytes(bytes, 0, length);
} /**
* 将字节数组全部写入缓存区
*/
public void WriteBytes(byte[] bytes)
{
WriteBytes(bytes, bytes.Length);
} /**
* 将一个ByteBuffer的有效字节区写入此缓存区中
*/
public void Write(ByteBuffer buffer)
{
if (buffer == null) return;
if (buffer.ReadableBytes() <= 0) return;
WriteBytes(buffer.ToArray());
} /**
* 写入一个int16数据
*/
public void WriteShort(short value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个uint16数据
*/
public void WriteUshort(ushort value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个int32数据
*/
public void WriteInt(int value)
{
//byte[] array = new byte[4];
//for (int i = 3; i >= 0; i--)
//{
// array[i] = (byte)(value & 0xff);
// value = value >> 8;
//}
//Array.Reverse(array);
//Write(array);
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个uint32数据
*/
public void WriteUint(uint value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个int64数据
*/
public void WriteLong(long value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个uint64数据
*/
public void WriteUlong(ulong value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个float数据
*/
public void WriteFloat(float value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 写入一个byte数据
*/
public void WriteByte(byte value)
{
lock (this)
{
int afterLen = writeIndex + 1;
int len = buf.Length;
FixSizeAndReset(len, afterLen);
buf[writeIndex] = value;
writeIndex = afterLen;
}
} /**
* 写入一个double类型数据
*/
public void WriteDouble(double value)
{
WriteBytes(flip(BitConverter.GetBytes(value)));
} /**
* 读取一个字节
*/
public byte ReadByte()
{
byte b = buf[readIndex];
readIndex++;
return b;
} /**
* 从读取索引位置开始读取len长度的字节数组
*/
private byte[] Read(int len)
{
byte[] bytes = new byte[len];
Array.Copy(buf, readIndex, bytes, 0, len);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
readIndex += len;
return bytes;
} /**
* 读取一个uint16数据
*/
public ushort ReadUshort()
{
return BitConverter.ToUInt16(Read(2), 0);
} /**
* 读取一个int16数据
*/
public short ReadShort()
{
return BitConverter.ToInt16(Read(2), 0);
} /**
* 读取一个uint32数据
*/
public uint ReadUint()
{
return BitConverter.ToUInt32(Read(4), 0);
} /**
* 读取一个int32数据
*/
public int ReadInt()
{
return BitConverter.ToInt32(Read(4), 0);
} /**
* 读取一个uint64数据
*/
public ulong ReadUlong()
{
return BitConverter.ToUInt64(Read(8), 0);
} /**
* 读取一个long数据
*/
public long ReadLong()
{
return BitConverter.ToInt64(Read(8), 0);
} /**
* 读取一个float数据
*/
public float ReadFloat()
{
return BitConverter.ToSingle(Read(4), 0);
} /**
* 读取一个double数据
*/
public double ReadDouble()
{
return BitConverter.ToDouble(Read(8), 0);
} /**
* 从读取索引位置开始读取len长度的字节到disbytes目标字节数组中
* @params disstart 目标字节数组的写入索引
*/
public void ReadBytes(byte[] disbytes, int disstart, int len)
{
int size = disstart + len;
for (int i = disstart; i < size; i++)
{
disbytes[i] = this.ReadByte();
}
} /**
* 清除已读字节并重建缓存区
*/
public void DiscardReadBytes()
{
if(readIndex <= 0) return;
int len = buf.Length - readIndex;
byte[] newbuf = new byte[len];
Array.Copy(buf, readIndex, newbuf, 0, len);
buf = newbuf;
writeIndex -= readIndex;
markReadIndex -= readIndex;
if (markReadIndex < 0)
{
markReadIndex = readIndex;
}
markWirteIndex -= readIndex;
if (markWirteIndex < 0 || markWirteIndex < readIndex || markWirteIndex < markReadIndex)
{
markWirteIndex = writeIndex;
}
readIndex = 0;
} /**
* 清空此对象
*/
public void Clear()
{
buf = new byte[buf.Length];
readIndex = 0;
writeIndex = 0;
markReadIndex = 0;
markWirteIndex = 0;
} /**
* 设置开始读取的索引
*/
public void SetReaderIndex(int index)
{
if (index < 0) return;
readIndex = index;
} /**
* 标记读取的索引位置
*/
public void MarkReaderIndex()
{
markReadIndex = readIndex;
} /**
* 标记写入的索引位置
*/
public void MarkWriterIndex()
{
markWirteIndex = writeIndex;
} /**
* 将读取的索引位置重置为标记的读取索引位置
*/
public void ResetReaderIndex()
{
readIndex = markReadIndex;
} /**
* 将写入的索引位置重置为标记的写入索引位置
*/
public void ResetWriterIndex()
{
writeIndex = markWirteIndex;
} /**
* 可读的有效字节数
*/
public int ReadableBytes()
{
return writeIndex - readIndex;
} /**
* 获取可读的字节数组
*/
public byte[] ToArray()
{
byte[] bytes = new byte[writeIndex];
Array.Copy(buf, 0, bytes, 0, bytes.Length);
return bytes;
} /**
* 获取缓存区大小
*/
public int GetCapacity()
{
return this.capacity;
}
}
//以下为ByteBuffer测试代码

ByteBuffer buf = ByteBuffer.Allocate(10);
buf.WriteInt(10000);
buf.WriteByte(10);
buf.WriteShort(1000); Console.WriteLine("-----------------------------"); Console.WriteLine(buf.ReadInt());
Console.WriteLine(buf.ReadByte());
Console.WriteLine(buf.ReadShort());

C#、Unity网络通信中基于字节码的自定义协议解码,C#版ByteBuffer的更多相关文章

  1. 移动开发首页业界资讯移动应用平台技术专题 输入您要搜索的内容 基于Java Socket的自定义协议,实现Android与服务器的长连接(二)

    在阅读本文前需要对socket以及自定义协议有一个基本的了解,可以先查看上一篇文章<基于Java Socket的自定义协议,实现Android与服务器的长连接(一)>学习相关的基础知识点. ...

  2. 开发 IDEA Plugin 引入探针,基于字节码插桩获取执行SQL

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 片面了! 一月三舟,托尔斯泰说:"多么伟大的作家,也不过就是在书写自己的片 ...

  3. eclipse中查看字节码

    1:在线安装ByteCode插件 打开Eclipse Go to"Help -> Install new Software... -> Work with:"中选择By ...

  4. 使用maven替换项目依赖中的字节码

    问题描述 我们偶尔会发现一些开源项目的问题,或者出于其他原因,想在某个dependency的代码中加几行或者删除几行来达到目的. 我这里遇到一个dubbo 2.7.3和open feign冲突的问题 ...

  5. 尚学堂 216 java中的字节码操作

    所谓的字节码操作就是操作我们已经加载的字节码 接下来我们重点来讲解javaassist类库 使用需要下载jar包,把jar包添加到对应的工程之后 package com.bjsxt.test; pub ...

  6. Intellij IDEA中查看字节码

    首先安装插件,这俩都勾上 Intellij IDEA 直接集成了一个工具菜单,可以直接查看字节码,打开 ByteCode 插件窗口方法如下:

  7. 尚学堂 217 java中的字节码操作2

    package com.bjsxt.test; @Author(name="gaoqi", year=2014) public class Emp { private int em ...

  8. Monodraw for Mac(基于 ASCII 码设计编辑工具)破解版安装

    1.软件简介    Monodrawp 是 macOS 系统上一款专为 Mac 设计的强大的 ASCII 码设计编辑器,纯文本历经几十年而不衰.Monodraw for mac 可以创建基于文本的艺术 ...

  9. 从字节码指令看重写在JVM中的实现

    Java是解释执行的.包含动态链接的特性.都给解析或执行期间提供了非常多灵活扩展的空间.面向对象语言的继承.封装和多态的特性,在JVM中是怎样进行编译.解析,以及通过字节码指令怎样确定方法调用的版本号 ...

随机推荐

  1. IOS之禁用UIWebView的默认交互行为

    本文转载至 http://my.oschina.net/hmj/blog/111344       UIKit提供UIWebView组件,允许开发者在App中嵌入Web页面.通过UIWebView组件 ...

  2. 2016/07/07 wamp中apache2.4.9允许外部访问的配置 重点是版本 版本不同配置效果不同

    wamp安装包中安装好服务器之后只能使用127.0.0.1来访问了,如果我们要设置多个站点或其它像192.168.1.1这种就需要进行一下修改,具体步骤如下.   wamp-apache2.4.9允许 ...

  3. Dubbo Spring Cloud Motan

    跨语言统一治理.Golang,谈谈另辟蹊径的开源RPC框架Motan_搜狐科技_搜狐网 https://www.sohu.com/a/207389967_467759

  4. eclipse调试第三方jar包需要源码的问题

    很多时候测试自己的jar包功能时,需要有一个测试工程导入该jar包,但是一般在调试的时候,需要跟进去看看步骤和逻辑是否正确,这个时候就需要在jar包的源码中下断点.最近刚好自己也会经常这样做,也遇到了 ...

  5. spawn类expect方法详解

    本文我们将介绍spawn类的基本方法expect方法,这个方法是用来匹配返回的结果,这个返回的结果是指子程序的返回结果,同时会将匹配的相关信息保存在spawn类的相关属性中. 基本属性包括三个,第一个 ...

  6. go 文件上传

    package main import ( "fmt" "io" "io/ioutil" "log" "net ...

  7. seventBus(封装) 一个巧妙的解决vue同级组件通讯的思路

    如果在你项目中需要多处用到同级组件通讯,而又不想去写繁琐的vuex,可以参考这个小思路.本人在写项目中琢磨出来的,感觉挺好用,分享一下. 1.在utils文件夹下添加BusEvent.js 注释已经很 ...

  8. Codeforces Round #373 (Div. 2) C. Efim and Strange Grade —— 贪心 + 字符串处理

    题目链接:http://codeforces.com/problemset/problem/719/C C. Efim and Strange Grade time limit per test 1 ...

  9. 一篇文章看懂iOS代码块Block

    block.png iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量.作为参数.作为返 ...

  10. 「LuoguP3796」 【模板】AC自动机(加强版)

    题目描述 有N个由小写字母组成的模式串以及一个文本串T.每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串T中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据. 每组数据的第一 ...