178 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
	
		
		
			
		
	
	
			178 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
	
| 
								 | 
							
								using System;
							 | 
						|||
| 
								 | 
							
								using DotNetty.Buffers;
							 | 
						|||
| 
								 | 
							
								using fec;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace fec.fec
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    public class FecEncode
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        /**消息包长度**/
							 | 
						|||
| 
								 | 
							
								        private readonly int dataShards;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        /**冗余包长度**/
							 | 
						|||
| 
								 | 
							
								        private readonly int parityShards;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        /** dataShards+parityShards **/
							 | 
						|||
| 
								 | 
							
								        private int shardSize;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //Protect Against Wrapped Sequence numbers
							 | 
						|||
| 
								 | 
							
								        private readonly long paws;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // next seqid
							 | 
						|||
| 
								 | 
							
								        private long next;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //count the number of datashards collected
							 | 
						|||
| 
								 | 
							
								        private int shardCount;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // record maximum data length in datashard
							 | 
						|||
| 
								 | 
							
								        private int maxSize;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // FEC header offset
							 | 
						|||
| 
								 | 
							
								        private readonly int headerOffset;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // FEC payload offset
							 | 
						|||
| 
								 | 
							
								        private readonly int payloadOffset;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //用完需要手动release
							 | 
						|||
| 
								 | 
							
								        private readonly IByteBuffer[] shardCache;
							 | 
						|||
| 
								 | 
							
								        private readonly IByteBuffer[] encodeCache;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private readonly IByteBuffer zeros;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private readonly ReedSolomon codec;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public FecEncode(int headerOffset, ReedSolomon codec, int mtu)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            this.dataShards = codec.getDataShardCount();
							 | 
						|||
| 
								 | 
							
								            this.parityShards = codec.getParityShardCount();
							 | 
						|||
| 
								 | 
							
								            this.shardSize = this.dataShards + this.parityShards;
							 | 
						|||
| 
								 | 
							
								            //this.paws = (Integer.MAX_VALUE/shardSize - 1) * shardSize;
							 | 
						|||
| 
								 | 
							
								            this.paws = 0xffffffffL / shardSize * shardSize;
							 | 
						|||
| 
								 | 
							
								            this.headerOffset = headerOffset;
							 | 
						|||
| 
								 | 
							
								            this.payloadOffset = headerOffset + Fec.fecHeaderSize;
							 | 
						|||
| 
								 | 
							
								            this.codec = codec;
							 | 
						|||
| 
								 | 
							
								            this.shardCache = new IByteBuffer[shardSize];
							 | 
						|||
| 
								 | 
							
								            this.encodeCache = new IByteBuffer[parityShards];
							 | 
						|||
| 
								 | 
							
								            zeros = PooledByteBufferAllocator.Default.DirectBuffer(mtu);
							 | 
						|||
| 
								 | 
							
								            zeros.WriteBytes(new byte[mtu]);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        /**
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     *  使用方法:
							 | 
						|||
| 
								 | 
							
								     *  1,入bytebuf后 把bytebuf发送出去,并释放bytebuf
							 | 
						|||
| 
								 | 
							
								     *  2,判断返回值是否为null,如果不为null发送出去并释放它
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     *  headerOffset +6字节fectHead +  2字节bodylenth(lenth-headerOffset-6)
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     * 1,对数据写入头标记为数据类型  markData
							 | 
						|||
| 
								 | 
							
								     * 2,写入消息长度
							 | 
						|||
| 
								 | 
							
								     * 3,获得缓存数据中最大长度,其他的缓存进行扩容到同样长度
							 | 
						|||
| 
								 | 
							
								     * 4,去掉头长度,进行fec编码
							 | 
						|||
| 
								 | 
							
								     * 5,对冗余字节数组进行标记为fec  makefec
							 | 
						|||
| 
								 | 
							
								     * 6,返回完整长度
							 | 
						|||
| 
								 | 
							
								     *
							 | 
						|||
| 
								 | 
							
								     *  注意: 传入的bytebuf如果需要释放在传入后手动释放。
							 | 
						|||
| 
								 | 
							
								     *  返回的bytebuf 也需要自己释放
							 | 
						|||
| 
								 | 
							
								     * @param byteBuf
							 | 
						|||
| 
								 | 
							
								     * @return
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								        public IByteBuffer[] encode(IByteBuffer byteBuf)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            markData(byteBuf, headerOffset);
							 | 
						|||
| 
								 | 
							
								            int sz = byteBuf.WriterIndex;
							 | 
						|||
| 
								 | 
							
								            byteBuf.SetShort(payloadOffset, sz - headerOffset - Fec.fecHeaderSizePlus2);
							 | 
						|||
| 
								 | 
							
								            this.shardCache[shardCount] = byteBuf.RetainedDuplicate();
							 | 
						|||
| 
								 | 
							
								            this.shardCount++;
							 | 
						|||
| 
								 | 
							
								            if (sz > this.maxSize)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                this.maxSize = sz;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            if (shardCount != dataShards)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                return null;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            //填充parityShards
							 | 
						|||
| 
								 | 
							
								            for (int i = 0; i < parityShards; i++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                IByteBuffer parityByte = PooledByteBufferAllocator.Default.DirectBuffer(this.maxSize);
							 | 
						|||
| 
								 | 
							
								                shardCache[i + dataShards] = parityByte;
							 | 
						|||
| 
								 | 
							
								                encodeCache[i] = parityByte;
							 | 
						|||
| 
								 | 
							
								                markParity(parityByte, headerOffset);
							 | 
						|||
| 
								 | 
							
								                parityByte.SetWriterIndex(this.maxSize);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            //按着最大长度不足补充0
							 | 
						|||
| 
								 | 
							
								            for (var i = 0; i < this.dataShards; i++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                var shard = shardCache[i];
							 | 
						|||
| 
								 | 
							
								                var left = this.maxSize - shard.WriterIndex;
							 | 
						|||
| 
								 | 
							
								                if (left <= 0)
							 | 
						|||
| 
								 | 
							
								                    continue;
							 | 
						|||
| 
								 | 
							
								                //是否需要扩容  会出现吗??
							 | 
						|||
| 
								 | 
							
								                //if(shard.capacity()<this.maxSize){
							 | 
						|||
| 
								 | 
							
								                //    ByteBuf newByteBuf = ByteBufAllocator.DEFAULT.buffer(this.maxSize);
							 | 
						|||
| 
								 | 
							
								                //    newByteBuf.writeBytes(shard);
							 | 
						|||
| 
								 | 
							
								                //    shard.release();
							 | 
						|||
| 
								 | 
							
								                //    shard = newByteBuf;
							 | 
						|||
| 
								 | 
							
								                //    shardCache[i] = shard;
							 | 
						|||
| 
								 | 
							
								                //}
							 | 
						|||
| 
								 | 
							
								                shard.WriteBytes(zeros, left);
							 | 
						|||
| 
								 | 
							
								                zeros.SetReaderIndex(0);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            codec.encodeParity(shardCache, payloadOffset, this.maxSize - payloadOffset);
							 | 
						|||
| 
								 | 
							
								            //释放dataShards
							 | 
						|||
| 
								 | 
							
								            for (int i = 0; i < dataShards; i++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                this.shardCache[i].Release();
							 | 
						|||
| 
								 | 
							
								                this.shardCache[i] = null;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            this.shardCount = 0;
							 | 
						|||
| 
								 | 
							
								            this.maxSize = 0;
							 | 
						|||
| 
								 | 
							
								            return this.encodeCache;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public void release()
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            this.shardSize = 0;
							 | 
						|||
| 
								 | 
							
								            this.next = 0;
							 | 
						|||
| 
								 | 
							
								            this.shardCount = 0;
							 | 
						|||
| 
								 | 
							
								            this.maxSize = 0;
							 | 
						|||
| 
								 | 
							
								            for (int i = 0; i < dataShards; i++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                var byteBuf = this.shardCache[i];
							 | 
						|||
| 
								 | 
							
								                byteBuf?.Release();
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            zeros.Release();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private void markData(IByteBuffer byteBuf, int offset)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            byteBuf.SetIntLE(offset,  (int)this.next);
							 | 
						|||
| 
								 | 
							
								            byteBuf.SetShortLE(offset + 4, Fec.typeData);
							 | 
						|||
| 
								 | 
							
								            this.next++;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        private void markParity(IByteBuffer byteBuf, int offset)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            byteBuf.SetIntLE(offset, (int) this.next);
							 | 
						|||
| 
								 | 
							
								            byteBuf.SetShortLE(offset + 4, Fec.typeParity);
							 | 
						|||
| 
								 | 
							
								            //if(next==this.paws){
							 | 
						|||
| 
								 | 
							
								            //    next=0;
							 | 
						|||
| 
								 | 
							
								            //}else{
							 | 
						|||
| 
								 | 
							
								            //    next++;
							 | 
						|||
| 
								 | 
							
								            //}
							 | 
						|||
| 
								 | 
							
								            this.next = (this.next + 1) % this.paws;
							 | 
						|||
| 
								 | 
							
								            //if(next+1>=this.paws) {
							 | 
						|||
| 
								 | 
							
								            //    this.next++;
							 | 
						|||
| 
								 | 
							
								            //    //this.next = (this.next + 1) % this.paws;
							 | 
						|||
| 
								 | 
							
								            //}
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |