Session3.0学习笔记(与2.0的差异)
请大家关注我的微博:@NormanLin_BadPixel坏像素
这里是2.0的传送门
首先我们看到,与2.0相比,多了Awake和Start的注册。虽然AWakeSystem和StartSystem也是3.0新加的,不过我们不难猜出来,这个跟之前的Event应该差不多。
private readonly Dictionary<uint, Action<PacketInfo>> requestCallback = new Dictionary<uint, Action<PacketInfo>>();
private readonly byte[] flagBytes = new byte[1];
private readonly List<byte[]> byteses = new List<byte[]>() {new byte[0], new byte[0], new byte[0]};
private readonly List<byte[]> rpcByteses = new List<byte[]>() { new byte[0], new byte[0], new byte[0], new byte[0] };
而且,requestCallback里面的回调函数也不再是传入object参数而是PacketInfo,比较短所以我就直接贴出来了。
public struct PacketInfo
{
public ushort Opcode;
public uint RpcId;
public byte[] Bytes;
public ushort Index;
public ushort Length;
}
多了一个存放flag的变量。
byteses多了一块数据并且多了存放RPC消息的rpcByteses。
这里我们不难猜出,多出来的这一块数据应该就是用来存放flag的了。
我们具体来看Run方法。
private void Run(Packet packet)
{
if (packet.Length < Packet.MinSize)
{
Log.Error($"message error length < {Packet.MinSize}, ip: {this.RemoteAddress}");
this.Network.Remove(this.Id);
return;
}
byte flag = packet.Flag();
ushort opcode = packet.Opcode();
PacketInfo packetInfo = new PacketInfo
{
Opcode = opcode,
Bytes = packet.Bytes
};
if ((flag & 0xC0) > 0)
{
uint rpcId = packet.RpcId();
packetInfo.RpcId = rpcId;
packetInfo.Index = Packet.RpcIdIndex + 4;
packetInfo.Length = (ushort)(packet.Length - packetInfo.Index);
// flag第2位表示这是rpc返回消息
if ((flag & 0x40) > 0)
{
Action<PacketInfo> action;
if (!this.requestCallback.TryGetValue(rpcId, out action))
{
return;
}
this.requestCallback.Remove(rpcId);
action(packetInfo);
return;
}
}
else
{
packetInfo.RpcId = 0;
packetInfo.Index = Packet.RpcIdIndex;
packetInfo.Length = (ushort)(packet.Length - packetInfo.Index);
}
this.Network.MessageDispatcher.Dispatch(this, packetInfo);
}
我们发现Run方法已经大变样了。首先取消了数据压缩,然后多了对Flag的判断。这里我们就可以知道,原来Packet里面的Flag标识的是是否是Rpc消息。
从作者的注释看来,Flag占1个字节 = 8位。我们用8位中的前两位来区分Rpc消息,如果前两位中至少有一位是1,则它是Rpc消息。在此基础上,如果第二位是1,则它是Rpc返回的消息,否则,它是Rpc请求的消息。
对这些消息的处理,代码里写的很清楚。我们疑惑的是,为什么
packetInfo.Index = Packet.RpcIdIndex + 4;
这可能关系到Rpc消息的组成结构,等我们之后遇到的时候再说吧。
之后的几个Call都跟2.0的很类似,不过多了Flag的设置,0x80 = 1000 0000。
这里说明一下作者注释的内容。
// 抛到外层不能再使用之前的byte[],因为那是Packet所有的,为了减少gc一直传到这个位置
byte[] newBytes = new byte[packetInfo.Length + packetInfo.Index];
Array.Copy(packetInfo.Bytes, 0, newBytes, 0, newBytes.Length);
packetInfo.Bytes = newBytes;
看过2.0的应该知道,2.0中的PacketParser获取数据会重新new一个Byte[],相当于获取到了一个副本,而3.0则是直接获取Packet中的数据引用。这样做是为了减少GC,但是在这个地方,我们需要Packet数据的副本,所以我们得经过这个步骤。我也不知道这两者到底哪个好,不过作者既然更新成了这种方式,必然有他的道理。但是我们也抱有疑惑,希望大佬能为我们解答,到底是在获取数据的时候创建一个副本好,还是在需要副本的时候经过这一系列的操作好? 如果能讲讲为什么那就更好了。
关于Replay方法,因为是对Rpc消息的回复,所以的设置Flag = 0x40 = 0100 0000
之后的SendMessage就很好理解了。
结束语
学而时习之——————Norman林