소켓 전송 protobuf 바이트 스트림의 예에 대한 자세한 설명

零下一度
풀어 주다: 2017-06-23 15:56:05
원래의
4229명이 탐색했습니다.

저작권 설명: 이 기사는 원본 기사이므로 재인쇄 시 신고해 주세요.

이전 기사에서는 주로 protobuf 바이트 스트림의 직렬화 및 구문 분석에 대해 설명했습니다. protobuf 개체는 바이트 스트림으로 직렬화된 후 직접 전달할 수 있지만, 실제로 프로젝트에서는 실제로 protobuf 바이트 스트림을 전송하는 것이 불가능합니다. 왜냐하면 소켓의 TCP 통신에는 고정 패킷 및 패킷 누락과 같은 몇 가지 매우 일반적인 문제가 있기 때문입니다. 소위 고정 패킷은 단순히 소켓이 여러 개의 작은 패킷을 병합하여 함께 보내는 것을 의미합니다. TCP는 연결 지향적이기 때문에 여러 패킷을 수신단에 보다 효율적으로 보내기 위해 송신단에서는 최적화 방법(Nagle 알고리즘)을 사용하여 작은 간격과 작은 데이터 볼륨의 여러 데이터를 병합한 후 큰 데이터 블록으로 패킷화합니다. . 패킷 누락은 버퍼 영역이 가득 찬 후 soket이 불완전한 패킷을 수신 측에 보내는 것을 의미합니다(제가 이해한 바에 따르면 끈적한 패킷과 누락된 패킷이 실제로 문제가 됩니다). 이와 같이 수신측이 한번에 수신한 데이터는 여러 개의 패킷이 될 수 있다. 이 문제를 해결하려면 데이터를 보내기 전에 패킷의 길이를 전송해야 한다. 따라서 패킷의 구조는 메시지 길이 + 메시지 내용이어야 합니다.

이 글에서는 데이터 스플라이싱에 대해 이야기하겠습니다. 유용한 정보는 다음과 같습니다

첫 번째 스플라이싱 데이터 패키지

 1     /// <summary> 2     /// 构建消息数据包 3     /// </summary> 4     /// <param name="protobufModel"></param> 5     byte[] BuildPackage(IExtensible protobufModel) 6     { 7         if (protobufModel != null) 8         { 9             byte[] b = ProtobufSerilizer.Serialize(protobufModel);10 11             ByteBuffer buf = ByteBuffer.Allocate(b.Length + 4);12             buf.WriteInt(b.Length);13             buf.WriteBytes(b);14             return buf.GetBytes();15         }16         return null;17     }
로그인 후 복사

코드에 사용된 ByteBuffer 도구는 C#에서는 제공되지 않습니다. 여기에서 발췌했는데, 작성자가 도구에 모든 바이트코드를 가져오는 메서드를 추가하지 않았기 때문에 GetBytes() 메서드를 추가했습니다

  1 using System;  2 using System.Collections.Generic;  3   4 /// <summary>  5 /// 字节缓冲处理类,本类仅处理大字节序  6 /// 警告,本类非线程安全  7 /// </summary>  8 public class ByteBuffer  9 { 10     //字节缓存区 11     private byte[] buf; 12     //读取索引 13     private int readIndex = 0; 14     //写入索引 15     private int writeIndex = 0; 16     //读取索引标记 17     private int markReadIndex = 0; 18     //写入索引标记 19     private int markWirteIndex = 0; 20     //缓存区字节数组的长度 21     private int capacity; 22  23     //对象池 24     private static List<ByteBuffer> pool = new List<ByteBuffer>(); 25     private static int poolMaxCount = 200; 26     //此对象是否池化 27     private bool isPool = false; 28  29     /// <summary> 30     /// 构造方法 31     /// </summary> 32     /// <param name="capacity">初始容量</param> 33     private ByteBuffer(int capacity) 34     { 35         buf = new byte[capacity]; 36         this.capacity = capacity; 37     } 38  39     /// <summary> 40     /// 构造方法 41     /// </summary> 42     /// <param name="bytes">初始字节数组</param> 43     private ByteBuffer(byte[] bytes) 44     { 45         buf = bytes; 46         this.capacity = bytes.Length; 47         this.readIndex = 0; 48         this.writeIndex = bytes.Length + 1; 49     } 50  51     /// <summary> 52     /// 构建一个capacity长度的字节缓存区ByteBuffer对象 53     /// </summary> 54     /// <param name="capacity">初始容量</param> 55     /// <returns>ByteBuffer对象</returns> 56     public static ByteBuffer Allocate(int capacity) 57     { 58         return new ByteBuffer(capacity); 59     } 60  61     /// <summary> 62     /// 构建一个以bytes为字节缓存区的ByteBuffer对象,一般不推荐使用 63     /// </summary> 64     /// <param name="bytes">初始字节数组</param> 65     /// <returns>ByteBuffer对象</returns> 66     public static ByteBuffer Allocate(byte[] bytes) 67     { 68         return new ByteBuffer(bytes); 69     } 70  71     /// <summary> 72     /// 获取一个池化的ByteBuffer对象,池化的对象必须在调用Dispose后才会推入池中,否则此方法等同于Allocate(int capacity)方法,此方法为线程安全的 73     /// </summary> 74     /// <param name="capacity">ByteBuffer对象的初始容量大小,如果缓存池中没有对象,则对象的容量大小为此值,否则为池中对象的实际容量值</param> 75     /// <returns></returns> 76     public static ByteBuffer GetFromPool(int capacity) 77     { 78         lock (pool) 79         { 80             ByteBuffer bbuf; 81             if (pool.Count == 0) 82             { 83                 bbuf = Allocate(capacity); 84                 bbuf.isPool = true; 85                 return bbuf; 86             } 87             int lastIndex = pool.Count - 1; 88             bbuf = pool[lastIndex]; 89             pool.RemoveAt(lastIndex); 90             if (!bbuf.isPool) 91             { 92                 bbuf.isPool = true; 93             } 94             return bbuf; 95         } 96     } 97  98     /// <summary> 99     /// 根据length长度,确定大于此leng的最近的2次方数,如length=7,则返回值为8100     /// </summary>101     /// <param name="length">参考容量</param>102     /// <returns>比参考容量大的最接近的2次方数</returns>103     private int FixLength(int length)104     {105         int n = 2;106         int b = 2;107         while (b < length)108         {109             b = 2 << n;110             n++;111         }112         return b;113     }114 115     /// <summary>116     /// 翻转字节数组,如果本地字节序列为低字节序列,则进行翻转以转换为高字节序列117     /// </summary>118     /// <param name="bytes">待转为高字节序的字节数组</param>119     /// <returns>高字节序列的字节数组</returns>120     private byte[] flip(byte[] bytes)121     {122         if (BitConverter.IsLittleEndian)123         {124             Array.Reverse(bytes);125         }126         return bytes;127     }128 129     /// <summary>130     /// 确定内部字节缓存数组的大小131     /// </summary>132     /// <param name="currLen">当前容量</param>133     /// <param name="futureLen">将来的容量</param>134     /// <returns>将来的容量</returns>135     private int FixSizeAndReset(int currLen, int futureLen)136     {137         if (futureLen > currLen)138         {139             //以原大小的2次方数的两倍确定内部字节缓存区大小140             int size = FixLength(currLen) * 2;141             if (futureLen > size)142             {143                 //以将来的大小的2次方的两倍确定内部字节缓存区大小144                 size = FixLength(futureLen) * 2;145             }146             byte[] newbuf = new byte[size];147             Array.Copy(buf, 0, newbuf, 0, currLen);148             buf = newbuf;149             capacity = newbuf.Length;150         }151         return futureLen;152     }153 154     /// <summary>155     /// 将bytes字节数组从startIndex开始的length字节写入到此缓存区156     /// </summary>157     /// <param name="bytes">待写入的字节数据</param>158     /// <param name="startIndex">写入的开始位置</param>159     /// <param name="length">写入的长度</param>160     public void WriteBytes(byte[] bytes, int startIndex, int length)161     {162         int offset = length - startIndex;163         if (offset <= 0) return;164         int total = offset + writeIndex;165         int len = buf.Length;166         FixSizeAndReset(len, total);167         for (int i = writeIndex, j = startIndex; i < total; i++, j++)168         {169             buf[i] = bytes[j];170         }171         writeIndex = total;172     }173 174     /// <summary>175     /// 将字节数组中从0到length的元素写入缓存区176     /// </summary>177     /// <param name="bytes">待写入的字节数据</param>178     /// <param name="length">写入的长度</param>179     public void WriteBytes(byte[] bytes, int length)180     {181         WriteBytes(bytes, 0, length);182     }183 184     /// <summary>185     /// 将字节数组全部写入缓存区186     /// </summary>187     /// <param name="bytes">待写入的字节数据</param>188     public void WriteBytes(byte[] bytes)189     {190         WriteBytes(bytes, bytes.Length);191     }192 193     /// <summary>194     /// 将一个ByteBuffer的有效字节区写入此缓存区中195     /// </summary>196     /// <param name="buffer">待写入的字节缓存区</param>197     public void Write(ByteBuffer buffer)198     {199         if (buffer == null) return;200         if (buffer.ReadableBytes() <= 0) return;201         WriteBytes(buffer.ToArray());202     }203 204     /// <summary>205     /// 写入一个int16数据206     /// </summary>207     /// <param name="value">short数据</param>208     public void WriteShort(short value)209     {210         WriteBytes(flip(BitConverter.GetBytes(value)));211     }212 213     /// <summary>214     /// 写入一个ushort数据215     /// </summary>216     /// <param name="value">ushort数据</param>217     public void WriteUshort(ushort value)218     {219         WriteBytes(flip(BitConverter.GetBytes(value)));220     }221 222     /// <summary>223     /// 写入一个int32数据224     /// </summary>225     /// <param name="value">int数据</param>226     public void WriteInt(int value)227     {228         //byte[] array = new byte[4];229         //for (int i = 3; i >= 0; i--)230         //{231         //    array[i] = (byte)(value & 0xff);232         //    value = value >> 8;233         //}234         //Array.Reverse(array);235         //Write(array);236         WriteBytes(flip(BitConverter.GetBytes(value)));237     }238 239     /// <summary>240     /// 写入一个uint32数据241     /// </summary>242     /// <param name="value">uint数据</param>243     public void WriteUint(uint value)244     {245         WriteBytes(flip(BitConverter.GetBytes(value)));246     }247 248     /// <summary>249     /// 写入一个int64数据250     /// </summary>251     /// <param name="value">long数据</param>252     public void WriteLong(long value)253     {254         WriteBytes(flip(BitConverter.GetBytes(value)));255     }256 257     /// <summary>258     /// 写入一个uint64数据259     /// </summary>260     /// <param name="value">ulong数据</param>261     public void WriteUlong(ulong value)262     {263         WriteBytes(flip(BitConverter.GetBytes(value)));264     }265 266     /// <summary>267     /// 写入一个float数据268     /// </summary>269     /// <param name="value">float数据</param>270     public void WriteFloat(float value)271     {272         WriteBytes(flip(BitConverter.GetBytes(value)));273     }274 275     /// <summary>276     /// 写入一个byte数据277     /// </summary>278     /// <param name="value">byte数据</param>279     public void WriteByte(byte value)280     {281         int afterLen = writeIndex + 1;282         int len = buf.Length;283         FixSizeAndReset(len, afterLen);284         buf[writeIndex] = value;285         writeIndex = afterLen;286     }287 288     /// <summary>289     /// 写入一个byte数据290     /// </summary>291     /// <param name="value">byte数据</param>292     public void WriteByte(int value)293     {294         byte b = (byte)value;295         WriteByte(b);296     }297 298     /// <summary>299     /// 写入一个double类型数据300     /// </summary>301     /// <param name="value">double数据</param>302     public void WriteDouble(double value)303     {304         WriteBytes(flip(BitConverter.GetBytes(value)));305     }306 307     /// <summary>308     /// 写入一个字符309     /// </summary>310     /// <param name="value"></param>311     public void WriteChar(char value)312     {313         WriteBytes(flip(BitConverter.GetBytes(value)));314     }315 316     /// <summary>317     /// 写入一个布尔型数据318     /// </summary>319     /// <param name="value"></param>320     public void WriteBoolean(bool value)321     {322         WriteBytes(flip(BitConverter.GetBytes(value)));323     }324 325     /// <summary>326     /// 读取一个字节327     /// </summary>328     /// <returns>字节数据</returns>329     public byte ReadByte()330     {331         byte b = buf[readIndex];332         readIndex++;333         return b;334     }335 336     /// <summary>337     /// 读取一个字节并转为int类型的数据338     /// </summary>339     /// <returns>int数据</returns>340     public int ReadByteToInt()341     {342         byte b = ReadByte();343         return (int)b;344     }345 346     /// <summary>347     /// 获取从index索引处开始len长度的字节348     /// </summary>349     /// <param name="index"></param>350     /// <param name="len"></param>351     /// <returns></returns>352     private byte[] Get(int index, int len)353     {354         byte[] bytes = new byte[len];355         Array.Copy(buf, index, bytes, 0, len);356         return flip(bytes);357     }358 359     /// <summary>360     /// 从读取索引位置开始读取len长度的字节数组361     /// </summary>362     /// <param name="len">待读取的字节长度</param>363     /// <returns>字节数组</returns>364     private byte[] Read(int len)365     {366         byte[] bytes = Get(readIndex, len);367         readIndex += len;368         return bytes;369     }370 371     /// <summary>372     /// 读取一个uint16数据373     /// </summary>374     /// <returns>ushort数据</returns>375     public ushort ReadUshort()376     {377         return BitConverter.ToUInt16(Read(2), 0);378     }379 380     /// <summary>381     /// 读取一个int16数据382     /// </summary>383     /// <returns>short数据</returns>384     public short ReadShort()385     {386         return BitConverter.ToInt16(Read(2), 0);387     }388 389     /// <summary>390     /// 读取一个uint32数据391     /// </summary>392     /// <returns>uint数据</returns>393     public uint ReadUint()394     {395         return BitConverter.ToUInt32(Read(4), 0);396     }397 398     /// <summary>399     /// 读取一个int32数据400     /// </summary>401     /// <returns>int数据</returns>402     public int ReadInt()403     {404         return BitConverter.ToInt32(Read(4), 0);405     }406 407     /// <summary>408     /// 读取一个uint64数据409     /// </summary>410     /// <returns>ulong数据</returns>411     public ulong ReadUlong()412     {413         return BitConverter.ToUInt64(Read(8), 0);414     }415 416     /// <summary>417     /// 读取一个long数据418     /// </summary>419     /// <returns>long数据</returns>420     public long ReadLong()421     {422         return BitConverter.ToInt64(Read(8), 0);423     }424 425     /// <summary>426     /// 读取一个float数据427     /// </summary>428     /// <returns>float数据</returns>429     public float ReadFloat()430     {431         return BitConverter.ToSingle(Read(4), 0);432     }433 434     /// <summary>435     /// 读取一个double数据436     /// </summary>437     /// <returns>double数据</returns>438     public double ReadDouble()439     {440         return BitConverter.ToDouble(Read(8), 0);441     }442 443     /// <summary>444     /// 读取一个字符445     /// </summary>446     /// <returns></returns>447     public char ReadChar()448     {449         return BitConverter.ToChar(Read(2), 0);450     }451 452     /// <summary>453     /// 读取布尔型数据454     /// </summary>455     /// <returns></returns>456     public bool ReadBoolean()457     {458         return BitConverter.ToBoolean(Read(1), 0);459     }460 461     /// <summary>462     /// 从读取索引位置开始读取len长度的字节到disbytes目标字节数组中463     /// </summary>464     /// <param name="disbytes">读取的字节将存入此字节数组</param>465     /// <param name="disstart">目标字节数组的写入索引</param>466     /// <param name="len">读取的长度</param>467     public void ReadBytes(byte[] disbytes, int disstart, int len)468     {469         int size = disstart + len;470         for (int i = disstart; i < size; i++)471         {472             disbytes[i] = this.ReadByte();473         }474     }475 476     /// <summary>477     /// 获取一个字节478     /// </summary>479     /// <param name="index"></param>480     /// <returns></returns>481     public byte GetByte(int index)482     {483         return buf[index];484     }485 486     /// <summary>487     /// 获取全部字节488     /// </summary>489     /// <returns></returns>490     public byte[] GetBytes()491     {492         return buf;493     }494 495     /// <summary>496     /// 获取一个双精度浮点数据,不改变数据内容497     /// </summary>498     /// <param name="index">字节索引</param>499     /// <returns></returns>500     public double GetDouble(int index)501     {502         return BitConverter.ToDouble(Get(0, 8), 0);503     }504 505     /// <summary>506     /// 获取一个浮点数据,不改变数据内容507     /// </summary>508     /// <param name="index">字节索引</param>509     /// <returns></returns>510     public float GetFloat(int index)511     {512         return BitConverter.ToSingle(Get(0, 4), 0);513     }514 515     /// <summary>516     /// 获取一个长整形数据,不改变数据内容517     /// </summary>518     /// <param name="index">字节索引</param>519     /// <returns></returns>520     public long GetLong(int index)521     {522         return BitConverter.ToInt64(Get(0, 8), 0);523     }524 525     /// <summary>526     /// 获取一个整形数据,不改变数据内容527     /// </summary>528     /// <param name="index">字节索引</param>529     /// <returns></returns>530     public int GetInt(int index)531     {532         return BitConverter.ToInt32(Get(0, 4), 0);533     }534 535     /// <summary>536     /// 获取一个短整形数据,不改变数据内容537     /// </summary>538     /// <param name="index">字节索引</param>539     /// <returns></returns>540     public int GetShort(int index)541     {542         return BitConverter.ToInt16(Get(0, 2), 0);543     }544 545 546     /// <summary>547     /// 清除已读字节并重建缓存区548     /// </summary>549     public void DiscardReadBytes()550     {551         if (readIndex <= 0) return;552         int len = buf.Length - readIndex;553         byte[] newbuf = new byte[len];554         Array.Copy(buf, readIndex, newbuf, 0, len);555         buf = newbuf;556         writeIndex -= readIndex;557         markReadIndex -= readIndex;558         if (markReadIndex < 0)559         {560             markReadIndex = readIndex;561         }562         markWirteIndex -= readIndex;563         if (markWirteIndex < 0 || markWirteIndex < readIndex || markWirteIndex < markReadIndex)564         {565             markWirteIndex = writeIndex;566         }567         readIndex = 0;568     }569 570     /// <summary>571     /// 清空此对象,但保留字节缓存数组(空数组)572     /// </summary>573     public void Clear()574     {575         buf = new byte[buf.Length];576         readIndex = 0;577         writeIndex = 0;578         markReadIndex = 0;579         markWirteIndex = 0;580         capacity = buf.Length;581     }582     583     /// <summary>584     /// 释放对象,清除字节缓存数组,如果此对象为可池化,那么调用此方法将会把此对象推入到池中等待下次调用585     /// </summary>586     public void Dispose()587     {588         readIndex = 0;589         writeIndex = 0;590         markReadIndex = 0;591         markWirteIndex = 0;592         if (isPool)593         {594             lock (pool)595             {596                 if (pool.Count < poolMaxCount)597                 {598                     pool.Add(this);599                 }600             }601         }602         else603         {604             capacity = 0;605             buf = null;606         }607     }608 609     /// <summary>610     /// 设置/获取读指针位置611     /// </summary>612     public int ReaderIndex613     {614         get615         {616             return readIndex;617         }618         set619         {620             if (value < 0) return;621             readIndex = value;622         }623     }624 625     /// <summary>626     /// 设置/获取写指针位置627     /// </summary>628     public int WriterIndex629     {630         get631         {632             return writeIndex;633         }634         set635         {636             if (value < 0) return;637             writeIndex = value;638         }639     }640 641     /// <summary>642     /// 标记读取的索引位置643     /// </summary>644     public void MarkReaderIndex()645     {646         markReadIndex = readIndex;647     }648 649     /// <summary>650     /// 标记写入的索引位置651     /// </summary>652     public void MarkWriterIndex()653     {654         markWirteIndex = writeIndex;655     }656 657     /// <summary>658     /// 将读取的索引位置重置为标记的读取索引位置659     /// </summary>660     public void ResetReaderIndex()661     {662         readIndex = markReadIndex;663     }664 665     /// <summary>666     /// 将写入的索引位置重置为标记的写入索引位置667     /// </summary>668     public void ResetWriterIndex()669     {670         writeIndex = markWirteIndex;671     }672 673     /// <summary>674     /// 可读的有效字节数675     /// </summary>676     /// <returns>可读的字节数</returns>677     public int ReadableBytes()678     {679         return writeIndex - readIndex;680     }681 682     /// <summary>683     /// 获取可读的字节数组684     /// </summary>685     /// <returns>字节数据</returns>686     public byte[] ToArray()687     {688         byte[] bytes = new byte[writeIndex];689         Array.Copy(buf, 0, bytes, 0, bytes.Length);690         return bytes;691     }692 693     /// <summary>694     /// 获取缓存区容量大小695     /// </summary>696     /// <returns>缓存区容量</returns>697     public int GetCapacity()698     {699         return this.capacity;700     }701 702     /// <summary>703     /// 简单的数据类型704     /// </summary>705     public enum LengthType706     {707         //byte类型708         BYTE,709         //short类型710         SHORT,711         //int类型712         INT713     }714 715     /// <summary>716     /// 写入一个数据717     /// </summary>718     /// <param name="value">待写入的数据</param>719     /// <param name="type">待写入的数据类型</param>720     public void WriteValue(int value, LengthType type)721     {722         switch (type)723         {724             case LengthType.BYTE:725                 this.WriteByte(value);726                 break;727             case LengthType.SHORT:728                 this.WriteShort((short)value);729                 break;730             default:731                 this.WriteInt(value);732                 break;733         }734     }735 736     /// <summary>737     /// 读取一个值,值类型根据type决定,int或short或byte738     /// </summary>739     /// <param name="type">值类型</param>740     /// <returns>int数据</returns>741     public int ReadValue(LengthType type)742     {743         switch (type)744         {745             case LengthType.BYTE:746                 return ReadByteToInt();747             case LengthType.SHORT:748                 return (int)ReadShort();749             default:750                 return ReadInt();751         }752     }753 754     /// <summary>755     /// 写入一个字符串756     /// </summary>757     /// <param name="content">待写入的字符串</param>758     /// <param name="lenType">写入的字符串长度类型</param>759     public void WriteUTF8String(string content, LengthType lenType)760     {761         byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(content);762         int max;763         if (lenType == LengthType.BYTE)764         {765             WriteByte(bytes.Length);766             max = byte.MaxValue;767         }768         else if (lenType == LengthType.SHORT)769         {770             WriteShort((short)bytes.Length);771             max = short.MaxValue;772         }773         else774         {775             WriteInt(bytes.Length);776             max = int.MaxValue;777         }778         if (bytes.Length > max)779         {780             WriteBytes(bytes, 0, max);781         }782         else783         {784             WriteBytes(bytes, 0, bytes.Length);785         }786     }787 788     /// <summary>789     /// 读取一个字符串790     /// </summary>791     /// <param name="len">需读取的字符串长度</param>792     /// <returns>字符串</returns>793     public string ReadUTF8String(int len)794     {795         byte[] bytes = new byte[len];796         this.ReadBytes(bytes, 0, len);797         return System.Text.UTF8Encoding.UTF8.GetString(bytes);798     }799 800     /// <summary>801     /// 读取一个字符串802     /// </summary>803     /// <param name="lenType">字符串长度类型</param>804     /// <returns>字符串</returns>805     public string ReadUTF8String(LengthType lenType)806     {807         int len = ReadValue(lenType);808         return ReadUTF8String(len);809     }810 811     /// <summary>812     /// 复制一个对象,具有与原对象相同的数据,不改变原对象的数据813     /// </summary>814     /// <returns></returns>815     public ByteBuffer Copy()816     {817         return Copy(0);818     }819 820     public ByteBuffer Copy(int startIndex)821     {822         if (buf == null)823         {824             return new ByteBuffer(16);825         }826         byte[] target = new byte[buf.Length - startIndex];827         Array.Copy(buf, startIndex, target, 0, target.Length);828         ByteBuffer buffer = new ByteBuffer(target.Length);829         buffer.WriteBytes(target);830         return buffer;831     }832 }
로그인 후 복사
코드 보기

물론 C#에는 ByteBuffer가 없지만 ,

      Send(          [] bytes =  [data.Length +          [] length = BitConverter.GetBytes(                                     Array.Copy(length, , bytes, ,          Array.Copy(data, , bytes,          mSocket.Send(bytes);
     }
로그인 후 복사

바이트 배열을 접합한 후 소켓의 송신 메서드를 사용하여 전송할 수 있습니다. 그러나 이 문서에서는 계속해서 데이터 수신 처리를 완료합니다.

데이터를 받는 순서는 메시지의 길이만큼 먼저 받은 다음, 메시지의 길이에 따라 지정된 길이의 메시지를 받는 것입니다

 1     void ReceiveMessage() 2     { 3           //上文说过,一个完整的消息是 消息长度+消息内容 4           //所以先创建一个长度4的字节数组,用于接收消息长度 5           byte[] recvBytesHead = GetBytesReceive(4); 6           //将消息长度字节组转为int数值 7           int bodyLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(recvBytesHead, 0)); 8           //根据消息长度接收指定长度的字节组,这个字节组就是完整的消息内容 9           byte[] recvBytesBody = GetBytesReceive(bodyLength);10           //最后反序列化消息的内容11           Test message = ProtobufSerilizer.DeSerialize<Test>(messageBody);12     }
로그인 후 복사
메시지를 받고 해결하는 방법은 GetBytesRecive 메서드입니다. 패킷이 끈적거리고 누락되는 문제는 다음과 같습니다

 1     /// <summary> 2     /// 接收数据并处理 3     /// </summary> 4     /// <param name="length"></param> 5     /// <returns></returns> 6     byte[] GetBytesReceive(int length) 7     { 8         //创建指定长度的字节组 9         byte[] recvBytes = new byte[length];10         //设置每次接收包的最大长度为1024个字节11         int packageMaxLength = 1024;12         //使用循环来保证接收的数据是完整的,如果剩余长度大于0,证明接收未完成13         while (length > 0)14         {15             //创建字节组,用于存放需要接收的字节流16             byte[] receiveBytes = new byte[length < packageMaxLength ? length : packageMaxLength];17             int iBytesBody = 0;18             //根据剩余需接收的长度来设置接收数据的长度19             if (length >= receiveBytes.Length)20                 iBytesBody = mSocket.Receive(receiveBytes, receiveBytes.Length, 0);21             else22                 iBytesBody = mSocket.Receive(receiveBytes, length, 0);23             receiveBytes.CopyTo(recvBytes, recvBytes.Length - length);24             //减去已接收的长度25             length -= iBytesBody;26         }27         return recvBytes;28     }
로그인 후 복사
여기서는 간단한 메시지 송수신이 기본적으로 완료되었습니다. 그러나 실제 프로젝트에서는 메시지가 하나만 존재하지 않습니다. 롱링크 프로젝트에서는 항상 메시지를 주고 받아야 하는데 어떻게 해야 할까요?

우리 모두 알고 있듯이 Unity UI의 표시는 메인 스레드에서만 실행될 수 있습니다. 그러나 메인 스레드에서 계속 메시지를 주고받는다면 경험이 극도로 저하되므로 다른 스레드를 열어야 합니다. 메시지 수신 및 전송을 담당합니다. 다음 기사에서는 멀티스레딩을 사용하여 소켓 통신을 완성하는 것입니다

위 내용은 소켓 전송 protobuf 바이트 스트림의 예에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!