第一部分:从FBitReader的字节流里面取32位PackedHeader和N位标识Ack History
1.PacketNotify.ReadHeader(Header, Reader),是怎么读的Header的。
在ReadHeader内部有利用Reader对象对operator<<的重载
在Reader对象operator<<的重载中会调用:
IsByteSwapping()的函数:判断是大端还是小端的字节序?、依据解析大概率会进入Serialize(&Value, sizeof(T)); T是:Value的类型。Dest是指针指向一个32位的数字。然后会来到Reader对象的SerializeBits( void* Dest, int64 LengthBits )函数,最后到了之前解析过的:appBitsCpy((uint8*)Dest, 0, Buffer.GetData(), (int32)Pos, (int32)LengthBits);在这里读了哪些数据赋值到了(读了Reader对象buffer里面的第一个字节到Header里面)
PackedHeader=64、105、139、60=01000000 01101001 10001011 00111100
3.ReadHeader()函数拿到包头PackedHeader后开始解包:
Data.Seq = FPackedHeader::GetSeq(PackedHeader):对PacketHeader右移18位&(0011111111111111)= 00000000 00000000 00010000 00011010=4122。右移18位意味着高位14位有效。
Data.AckedSeq = FPackedHeader::GetAckedSeq(PackedHeader):右移4位&(0011111111111111)=00000100 00000110 10011000 10110011&(0011111111111111)=
Data.HistoryWordCount = FPackedHeader::GetHistoryWordCount(PackedHeader) + 1;
因此32位的PacketHeader,14位用于表示Seq、14位用于表示AckedSeq、4位用于标识HistoryWordCount。
4.依据HistoryWordCount来判断继续从FBitReader中读几位用于标识Ack History
HistoryWordCount最大等于8,代表有8个32位用于标识AckHistory。
5.往后读取一个比特表示是否bHasPacketInfoPayload
bHasPacketInfoPayload = Reader.ReadBit() == 1u;
6.如果bHasPacketInfoPayload为true读取Read jitter clock time from the packet header
uint32 PacketJitterClockTimeMS = 0;
Reader.SerializeInt(PacketJitterClockTimeMS, UE4_NetConnectionPrivate::MaxJitterClockTimeValue + 1);
这里并不是从FBitReader对象Reader的字节流中读32位存到PacketJitterClockTimeMS,而是一直读取位并通过或操作保存该值直到大于等于:UE4_NetConnectionPrivate::MaxJitterClockTimeValue + 1,时停止读取。注意这里从字节流中读取位的时候并不是从高位向低位的顺序读而是从低位向高位读。
6.执行ProcessJitter:如果bIsReinjectedPacket为false那么执行
这个函数里面做的事情就是计算平均时间差并保存。
7.根据接收到的Packet的序列号和上次收到Packet的序列号算出PacketSequenceDelta
packetSequenceDelta大于0说明收包正常,可以进行下一步。
判断是否有
8.如果有Packet没有按增序到达,但也并没有认为是发生了丢包,那么会Cache这个Packet
9.NetConnection的几个关于Packet的成员变量:
InPacketsLost:丢失了几个Packet,当上一次收到的序列号是1,下一次收到的3时,可知丢失了1个Packet。
InTotalPacketsLost:总共丢失的几个Packet。
InPacketId:???
10.如果bHasPacketInfoPayLoad为True的话。BitReader还有几个比特记录了额外的消息
在ReadPacketInfo(Reader, bHasPacketInfoPayload);里面会读出来
11.PacketNotify.Update(Header, HandlePacketNotification);
在PacketNotify.Update(Header, HandlePacketNotification)函数内做的几个事情:
1.计算得到当前接收到的AckedSeq和OutAckSeq的差值,在这里等于:5197-5195等于2;
2.调用UpdateInAckSeqAck()函数,传入上面的差值和当前接收到的AckedSeq
有一个AckRecord数据成员,是一个循环队列。每发出一个Packet就会记录,目前队列里面的内容大概为:5196、5197、5198、5199
先pop出来一个,将5196对于的数据移出队列。然后拿到队头5197的数据:FSentAckData AckData,并pop出队列
如果AckData的OutSeq等于接收到的AckedSeq,那么就将AckData中的InAckSeq返回,这个InAckSeq等于7981,然后赋值给NetConnection的InAckSeqAck。
也就是说明了在FSendAckData中,5197是对应了7981的。5197的Ack是对7981的Ack的Ack,二次确认的意思?
3.while循环对5195、5196、5197进行处理
12.开始拆分Packet中包含的Bunches
1.与bFlushingPacketOrderCache和PacketOrderCache相关的缓存Missing Packet
2.