Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How socket transmits protobuf byte streams

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

Editor to share with you how socket transmits protobuf byte streams, I believe most people don't know much about it, so share this article for your reference. I hope you can learn a lot after reading this article. Let's learn about it together.

The first stitching packet

1 / / 2 / / build message packet 3 / 4 / 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}

The ByteBuffer tool used in the code is provided in java, but not in c #, the source code is extracted, but the author did not add a method to get all the bytecode in the tool, so he added a GetBytes () method

1 using System; 2 using System.Collections.Generic; 3 4 / 5 / byte buffer processing class, this class only deals with large byte order 6 / warnings, this class is non-thread safe 7 / / 8 public class ByteBuffer 9 {10 / / byte cache 11 private byte [] buf; 12 / / read index 13 private int readIndex = 0; 14 / / write index 15 private int writeIndex = 0 16 / / read index tag 17 private int markReadIndex = 0; 18 / write index tag 19 private int markWirteIndex = 0; 20 / / length of cache byte array 21 private int capacity; 22 23 / / object pool 24 private static List pool = new List (); 25 private static int poolMaxCount = 200; 26 / / whether this object is pooled 27 private bool isPool = false 28 29 / / 30 / / Construction method 31 / 32 / / initial capacity 33 private ByteBuffer (int capacity) 34 {35 buf = new byte [capacity]; 36 this.capacity = capacity 37} 38 39 / / 40 / / Construction method 41 / 42 / / initial byte array 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 / / 52 / / build a capacity length byte cache ByteBuffer object 53 / / 54 / initial capacity 55 / ByteBuffer object 56 public static ByteBuffer Allocate (int capacity) 57 {58 return new ByteBuffer (capacity) 59} 60 61 / / 62 / / build a ByteBuffer object with bytes as byte cache. It is generally not recommended to use 63 / / 64 / initial byte array 65 / ByteBuffer object 66 public static ByteBuffer Allocate (byte [] bytes) 67 {68 return new ByteBuffer (bytes) 69} 70 71 / 72 / / get a pooled ByteBuffer object. The pooled object will not be pushed into the pool until Dispose is called, otherwise this method is equivalent to the Allocate (int capacity) method, which is the initial capacity size of the thread-safe 73 / / 74 / ByteBuffer object. If there are no objects in the cache pool, the object's capacity size is this value. Otherwise, the actual capacity of the object in the pool is 75 / 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 / / 99 / / according to the length of the length, determine the nearest power 2 greater than this leng. For example, if length=7, the return value is 8100 / / 1011010 / / reference capacity 102 / the nearest power 103private int FixLength (int length) 10105int n = 2106 int b = 2. 107 while (b)

< length)108 {109 b = 2 currLen)138 {139 //以原大小的2次方数的两倍确定内部字节缓存区大小140 int size = FixLength(currLen) * 2;141 if (futureLen >

Size) 14414 / / determine the internal byte cache size by twice the 2 power of the future size. 14414 size = FixLength (futureLen) * 2bot 145} 146byte [] newbuf = new byte [size]; 147Array.Copy (buf, 0, newbuf, 0, currLen); 148buf = newbuf 149capacity = newbuf.Length;150} 151return futureLen Write the bytes byte array from startIndex to the starting position of the byte data to be written in this cache. 159The length of the write is 160public void WriteBytes (byte [] bytes, int startIndex, int length) 166162int offset = length-startIndex;163 if (offset > 8). 234 / / Array.Reverse (array); 235 / / Write (array); 236 WriteBytes (flip (BitConverter.GetBytes (value); 237} 238239 / / 240 / write a uint32 data 241 / 242 / / uint data 243 public void WriteUint (uint value) 244 {245 WriteBytes (flip (BitConverter.GetBytes (value) Write an int64 data 250 / / 251 / long data 252 public void WriteLong (long value) 253 {254 WriteBytes (flip (BitConverter.GetBytes (value) Write a uint64 data 259 / / 260 / ulong data 261 public void WriteUlong (ulong value) 262 {263 WriteBytes (flip (BitConverter.GetBytes (value) 264} 265,266 / / 267 / / write a float data 268 / / 269 / float data 270 public void WriteFloat (float value) 271 {272 WriteBytes (flip (BitConverter.GetBytes (value) Write a byte data 277 / / 278 / byte data 279 public void WriteByte (byte value) 280 {281 int afterLen = writeIndex + 1 afterLen 282 int len = buf.Length;283 FixSizeAndReset (len, afterLen); 284 buf [writeIndex] = value;285 writeIndex = afterLen Write a byte data 290 / / 291 / byte data 292 public void WriteByte (int value) 293 {294 byte b = (byte) value;295 WriteByte (b) Write a double type data 300 / / 301 / / double data 302 public void WriteDouble (double value) 303 {304 WriteBytes (flip (BitConverter.GetBytes (value) Write a character 309 / / 310 / 311 public void WriteChar (char value) 312 {313 WriteBytes (flip (BitConverter.GetBytes (value) 314} 315316 / / 317 / / write a Boolean data 318 / / 319 / 320 public void WriteBoolean (bool value) 321 {322 WriteBytes (flip (BitConverter.GetBytes (value) 323} 324 325 / / 326 / / read a byte 327 / / 328 / byte data 329 public byte ReadByte () 330 {331 byte b = buf [readIndex]; 332 readIndex++;333 return b 334} 335 336 / 337 / / data read one byte and converted to int data 338 / / 339 / / int data 340 public int ReadByteToInt () 341 {342 byte b = ReadByte (); 343 return (int) b 344} 345346 / 347 / / get the byte 348 / / 349 / / 350 / / 351 / 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) Read len length byte array 361 / / 362 / / byte array 363 / byte array 364 private byte [] Read (int len) 365 {366 byte [] bytes = Get (readIndex, len); 367 readIndex + = len;368 return bytes Read a uint16 data 373 / / 374 / ushort data 375 public ushort ReadUshort () 376 {377 return BitConverter.ToUInt16 (Read (2), 0) Read an int16 data 382 / / 383 / short data 384 public short ReadShort () 385 {386 return BitConverter.ToInt16 (Read (2), 0) Read a uint32 data 391 / / 392 / uint data 393 public uint ReadUint () 394 {395 return BitConverter.ToUInt32 (Read (4), 0) Read an int32 data 400 / / 401 / int data 402 public int ReadInt () 403 {404 return BitConverter.ToInt32 (Read (4), 0) Read a uint64 data 409 / / 410 / ulong data 411 public ulong ReadUlong () 412 {413 return BitConverter.ToUInt64 (Read (8), 0) 414} 415 416 / / 417 / / read a long data 418 / / 419 / long data 420 public long ReadLong () 421 {422 return BitConverter.ToInt64 (Read (8), 0) 423} 424 425 / / 426 / / read a float data 427 / / 428 / float data 429 public float ReadFloat () 430 {431 return BitConverter.ToSingle (Read (4), 0) Read a double data 436 / / 437 / double data 438 public double ReadDouble () 439 {440 return BitConverter.ToDouble (Read (8), 0) 441} 442 443 / / 444 / / read a character 445 / / 446 / 447 public char ReadChar () 448 {449 return BitConverter.ToChar (Read (2), 0) Reading Boolean data 454 / / 455 / 456 public bool ReadBoolean () 457 {458 return BitConverter.ToBoolean (Read (1), 0) 459} 460 461 / 462 / bytes of len length read from the read index position to the disbytes target byte array 463 / / 464 / read bytes will be stored in this byte array 465 / target byte array write index 466 / read length 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 /// 477 /// 获取一个字节478 /// 479 /// 480 /// 481 public byte GetByte(int index)482 {483 return buf[index];484 }485 486 /// 487 /// 获取全部字节488 /// 489 /// 490 public byte[] GetBytes()491 {492 return buf;493 }494 495 /// 496 /// 获取一个双精度浮点数据,不改变数据内容497 /// 498 /// 字节索引499 /// 500 public double GetDouble(int index)501 {502 return BitConverter.ToDouble(Get(0, 8), 0);503 }504 505 /// 506 /// 获取一个浮点数据,不改变数据内容507 /// 508 /// 字节索引509 /// 510 public float GetFloat(int index)511 {512 return BitConverter.ToSingle(Get(0, 4), 0);513 }514 515 /// 516 /// 获取一个长整形数据,不改变数据内容517 /// 518 /// 字节索引519 /// 520 public long GetLong(int index)521 {522 return BitConverter.ToInt64(Get(0, 8), 0);523 }524 525 /// 526 /// 获取一个整形数据,不改变数据内容527 /// 528 /// 字节索引529 /// 530 public int GetInt(int index)531 {532 return BitConverter.ToInt32(Get(0, 4), 0);533 }534 535 /// 536 /// 获取一个短整形数据,不改变数据内容537 /// 538 /// 字节索引539 /// 540 public int GetShort(int index)541 {542 return BitConverter.ToInt16(Get(0, 2), 0);543 }544 545 546 /// 547 /// 清除已读字节并重建缓存区548 /// 549 public void DiscardReadBytes()550 {551 if (readIndex max)779 {780 WriteBytes(bytes, 0, max);781 }782 else783 {784 WriteBytes(bytes, 0, bytes.Length);785 }786 }787 788 /// 789 /// 读取一个字符串790 /// 791 /// 需读取的字符串长度792 /// 字符串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 /// 801 /// 读取一个字符串802 /// 803 /// 字符串长度类型804 /// 字符串805 public string ReadUTF8String(LengthType lenType)806 {807 int len = ReadValue(lenType);808 return ReadUTF8String(len);809 }810 811 /// 812 /// 复制一个对象,具有与原对象相同的数据,不改变原对象的数据813 /// 814 /// 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 } View Code 当然,c#中虽然没有ByteBuffer,但也有拼接字节数组的方法,比如 Send( [] bytes = [data.Length + [] length = BitConverter.GetBytes( Array.Copy(length, , bytes, , Array.Copy(data, , bytes, mSocket.Send(bytes); } 字节数组拼接好后,就可以使用socket的send方法发送了,不过这一篇先继续讲完接收数据的处理 接收数据的顺序是先接收消息长度,然后根据消息长度接收指定长度的消息 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(messageBody);12 } GetBytesRecive方法用于接收消息,并解决粘包、少包的问题,代码如下 1 /// 2 /// 接收数据并处理 3 /// 4 /// 5 /// 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 / / create a byte group to store the byte streams that need to be received 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 / minus the length received 25 length-= iBytesBody;26} 27 return recvBytes;28}

At this point, the simple sending and receiving of messages is basically done, but in the actual project, we certainly have more than one message. If it is a long-linked project, we need to receive and send messages all the time. What should we do?

The display on unity's UI can only be performed in the main thread, but if we keep receiving and sending messages on the main thread, the experience will be very poor, so we have to start a separate thread to receive and send messages.

These are all the contents of the article "how socket transmits protobuf byte streams". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report