Home Backend Development C#.Net Tutorial Examples of solving problems with TCP sticky packets in C#

Examples of solving problems with TCP sticky packets in C#

Jul 17, 2017 am 11:06 AM
.net Example

This article mainly introduces in detail the solution to the TCP sticky problem in C#, which has certain reference value. Interested friends can refer to it

1. TCP Sticky The principle of packet generation

1.TCP sticky packet means that several packets of data sent by the sender are glued into one packet when the receiver receives it. From the receiving buffer, the header of the latter packet of data follows immediately The end of the previous packet of data. There are many reasons for the sticky phenomenon. It may be caused by the sender or the receiver.

2. The sticky packet caused by the sender is caused by the TCP protocol itself. In order to improve the transmission efficiency of TCP, the sender often has to collect enough data before sending a packet of data. If the data sent several times in a row is very small, usually TCP will combine the data into one packet according to the optimization algorithm and send it out at once, so that the receiver receives the sticky packet data. The sticky packet caused by the receiver is because the user process of the receiver does not receive the data in time, which leads to the sticky packet phenomenon.

3. This is because the receiver first puts the received data in the system receiving buffer, and the user process takes the data from the buffer. If the next packet of data arrives, the previous packet of data has not been received by the user process. Take it away, then the next packet of data is placed in the system receiving buffer after receiving the previous packet of data, and the user process fetches data from the system receiving buffer according to the preset buffer size, so that multiple packets are fetched at one time data. ,

2. Solution principle and code implementation

1. Use the header (fixed length, which contains the length of the package body, dynamically obtained when sending) + package body transmission mechanism. As shown in the figure

HeaderSize stores the length of the packet body, and the HeaderSize itself is a fixed length of 4 bytes;

A complete data packet (L) = HeaderSize+BodySize;

2. Subpackaging algorithm

The basic idea is to first forcibly convert the received data stream to be processed, that is, the system buffer data (length set to M) into a predetermined structure data form, and extract the structural data length field L from it, and then calculate the first packet data length according to the packet header.

      M=System buffer size; L=Data packet sent by the user=HeaderSize+BodySize;

1) If L

2) If L=M, it means that the data stream content is exactly a complete structure data (that is, the user-defined buffer is equal to the system receive buffer size), directly Just store it in the temporary buffer.

3) If L>M, it means that the content of the data stream is not enough to form a complete structured data and needs to be merged with the next packet of data before processing.

4) The following is the code implementation (the server side of the HP-SOCKET framework receives data)

int headSize = 4;//包头长度 固定4
  byte[] surplusBuffer = null;//不完整的数据包,即用户自定义缓冲区
  /// <summary>
  /// 接收客户端发来的数据
  /// </summary>
  /// <param name="connId">每个客户的会话ID</param>
  /// <param name="bytes">缓冲区数据</param>
  /// <returns></returns>
  private HandleResult OnReceive(IntPtr connId, byte[] bytes) 
  {
   //bytes 为系统缓冲区数据
   //bytesRead为系统缓冲区长度
   int bytesRead = bytes.Length;
   if (bytesRead > 0)
   {
    if (surplusBuffer == null)//判断是不是第一次接收,为空说是第一次
     surplusBuffer = bytes;//把系统缓冲区数据放在自定义缓冲区里面
    else
     surplusBuffer = surplusBuffer.Concat(bytes).ToArray();//拼接上一次剩余的包
    //已经完成读取每个数据包长度
    int haveRead = 0;
    //这里totalLen的长度有可能大于缓冲区大小的(因为 这里的surplusBuffer 是系统缓冲区+不完整的数据包)
    int totalLen = surplusBuffer.Length;
    while (haveRead <= totalLen)
    {
     //如果在N此拆解后剩余的数据包连一个包头的长度都不够
     //说明是上次读取N个完整数据包后,剩下的最后一个非完整的数据包
     if (totalLen - haveRead < headSize)
     {
      byte[] byteSub = new byte[totalLen - haveRead];
      //把剩下不够一个完整的数据包存起来
      Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead);
      surplusBuffer = byteSub;
      totalLen = 0;
      break;
     }
     //如果够了一个完整包,则读取包头的数据
     byte[] headByte = new byte[headSize];
     Buffer.BlockCopy(surplusBuffer, haveRead, headByte, 0, headSize);//从缓冲区里读取包头的字节
     int bodySize = BitConverter.ToInt32(headByte, 0);//从包头里面分析出包体的长度

     //这里的 haveRead=等于N个数据包的长度 从0开始;0,1,2,3....N
     //如果自定义缓冲区拆解N个包后的长度 大于 总长度,说最后一段数据不够一个完整的包了,拆出来保存
     if (haveRead + headSize + bodySize > totalLen)
     {
      byte[] byteSub = new byte[totalLen - haveRead];
      Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead);
      surplusBuffer = byteSub;
      break;
     }
     else
     {
      //挨个分解每个包,解析成实际文字
      String strc = Encoding.UTF8.GetString(surplusBuffer, haveRead + headSize, bodySize);
      //AddMsg(string.Format(" > [OnReceive] -> {0}", strc));
      //依次累加当前的数据包的长度
      haveRead = haveRead + headSize + bodySize;
      if (headSize + bodySize == bytesRead)//如果当前接收的数据包长度正好等于缓冲区长度,则待拼接的不规则数据长度归0
      {
       surplusBuffer = null;//设置空 回到原始状态
       totalLen = 0;//清0
      }
     }
    }
   }
   return HandleResult.Ok;
  }
Copy after login

At this time, the work of unpacking and parsing text is completed. But it's not actually finished yet. If this code is for the client to receive data from the server, it will be fine.

Look carefully at the IntPtr connId session ID of each connection

private HandleResult OnReceive(IntPtr connId, byte[] bytes)
{
}
Copy after login

But the server side also needs to distinguish which session each data packet is generated, because the server side is multi-threaded and multi-user. mode, the first packet and the second may be data from different sessions, so the above code only works in single session mode.

I am going to solve this problem below.

Using c#safetyConcurrentDictionary,

latest code

//线程安全的字典
  ConcurrentDictionary<IntPtr, byte[]> dic = new ConcurrentDictionary<IntPtr, byte[]>();
  int headSize = 4;//包头长度 固定4
  /// <summary>
  /// 接收客户端发来的数据
  /// </summary>
  /// <param name="connId">每个客户的会话ID</param>
  /// <param name="bytes">缓冲区数据</param>
  /// <returns></returns>
  private HandleResult OnReceive(IntPtr connId, byte[] bytes) 
  {
   //bytes 为系统缓冲区数据
   //bytesRead为系统缓冲区长度
   int bytesRead = bytes.Length;
   if (bytesRead > 0)
   {
    byte[] surplusBuffer = null;
    if (dic.TryGetValue(connId, out surplusBuffer))
    {
     byte[] curBuffer = surplusBuffer.Concat(bytes).ToArray();//拼接上一次剩余的包
     //更新会话ID 的最新字节
     dic.TryUpdate(connId, curBuffer, surplusBuffer);
     surplusBuffer = curBuffer;//同步
    }
    else
    {
     //添加会话ID的bytes
     dic.TryAdd(connId, bytes);
     surplusBuffer = bytes;//同步
    }

    //已经完成读取每个数据包长度
    int haveRead = 0;
    //这里totalLen的长度有可能大于缓冲区大小的(因为 这里的surplusBuffer 是系统缓冲区+不完整的数据包)
    int totalLen = surplusBuffer.Length;
    while (haveRead <= totalLen)
    {
     //如果在N此拆解后剩余的数据包连一个包头的长度都不够
     //说明是上次读取N个完整数据包后,剩下的最后一个非完整的数据包
     if (totalLen - haveRead < headSize)
     {
      byte[] byteSub = new byte[totalLen - haveRead];
      //把剩下不够一个完整的数据包存起来
      Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead);
      dic.TryUpdate(connId, byteSub, surplusBuffer);
      surplusBuffer = byteSub;
      totalLen = 0;
      break;
     }
     //如果够了一个完整包,则读取包头的数据
     byte[] headByte = new byte[headSize];
     Buffer.BlockCopy(surplusBuffer, haveRead, headByte, 0, headSize);//从缓冲区里读取包头的字节
     int bodySize = BitConverter.ToInt32(headByte, 0);//从包头里面分析出包体的长度

     //这里的 haveRead=等于N个数据包的长度 从0开始;0,1,2,3....N
     //如果自定义缓冲区拆解N个包后的长度 大于 总长度,说最后一段数据不够一个完整的包了,拆出来保存
     if (haveRead + headSize + bodySize > totalLen)
     {
      byte[] byteSub = new byte[totalLen - haveRead];
      Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead);
      dic.TryUpdate(connId, byteSub, surplusBuffer);
      surplusBuffer = byteSub;
      break;
     }
     else
     {
      //挨个分解每个包,解析成实际文字
      String strc = Encoding.UTF8.GetString(surplusBuffer, haveRead + headSize, bodySize);
      AddMsg(string.Format(" > {0}[OnReceive] -> {1}", connId, strc));
      //依次累加当前的数据包的长度
      haveRead = haveRead + headSize + bodySize;
      if (headSize + bodySize == bytesRead)//如果当前接收的数据包长度正好等于缓冲区长度,则待拼接的不规则数据长度归0
      {
       byte[] xbtye=null;
       dic.TryRemove(connId, out xbtye);
       surplusBuffer = null;//设置空 回到原始状态
       totalLen = 0;//清0
      }
     }
    }
   }
   return HandleResult.Ok;
  }
Copy after login

This solves the problem, multiple clients Reception confusion caused by sessions. At this point all work is completed. The above code is just for reference and learning, if you really don’t want to go to such trouble. You can directly use the PACK model of the HP-SOCKET communication framework, which automatically solves the problem of sticky packets.

The above is the detailed content of Examples of solving problems with TCP sticky packets in C#. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Introduction to Python functions: Introduction and examples of exec function Introduction to Python functions: Introduction and examples of exec function Nov 03, 2023 pm 02:09 PM

Introduction to Python functions: Introduction and examples of exec function Introduction: In Python, exec is a built-in function that is used to execute Python code stored in a string or file. The exec function provides a way to dynamically execute code, allowing the program to generate, modify, and execute code as needed during runtime. This article will introduce how to use the exec function and give some practical code examples. How to use the exec function: The basic syntax of the exec function is as follows: exec

Go language indentation specifications and examples Go language indentation specifications and examples Mar 22, 2024 pm 09:33 PM

Indentation specifications and examples of Go language Go language is a programming language developed by Google. It is known for its concise and clear syntax, in which indentation specifications play a crucial role in the readability and beauty of the code. effect. This article will introduce the indentation specifications of the Go language and explain in detail through specific code examples. Indentation specifications In the Go language, tabs are used for indentation instead of spaces. Each level of indentation is one tab, usually set to a width of 4 spaces. Such specifications unify the coding style and enable teams to work together to compile

Oracle DECODE function detailed explanation and usage examples Oracle DECODE function detailed explanation and usage examples Mar 08, 2024 pm 03:51 PM

The DECODE function in Oracle is a conditional expression that is often used to return different results based on different conditions in query statements. This article will introduce the syntax, usage and sample code of the DECODE function in detail. 1. DECODE function syntax DECODE(expr,search1,result1[,search2,result2,...,default]) expr: the expression or field to be compared. search1,

Introduction to Python functions: Usage and examples of abs function Introduction to Python functions: Usage and examples of abs function Nov 03, 2023 pm 12:05 PM

Introduction to Python functions: usage and examples of the abs function 1. Introduction to the usage of the abs function In Python, the abs function is a built-in function used to calculate the absolute value of a given value. It can accept a numeric argument and return the absolute value of that number. The basic syntax of the abs function is as follows: abs(x) where x is the numerical parameter to calculate the absolute value, which can be an integer or a floating point number. 2. Examples of abs function Below we will show the usage of abs function through some specific examples: Example 1: Calculation

What are the employment prospects of C#? What are the employment prospects of C#? Oct 19, 2023 am 11:02 AM

Whether you are a beginner or an experienced professional, mastering C# will pave the way for your career.

Share several .NET open source AI and LLM related project frameworks Share several .NET open source AI and LLM related project frameworks May 06, 2024 pm 04:43 PM

The development of artificial intelligence (AI) technologies is in full swing today, and they have shown great potential and influence in various fields. Today Dayao will share with you 4 .NET open source AI model LLM related project frameworks, hoping to provide you with some reference. https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel is an open source software development kit (SDK) designed to integrate large language models (LLM) such as OpenAI, Azure

Introduction to Python functions: Usage and examples of isinstance function Introduction to Python functions: Usage and examples of isinstance function Nov 04, 2023 pm 03:15 PM

Introduction to Python functions: Usage and examples of the isinstance function Python is a powerful programming language that provides many built-in functions to make programming more convenient and efficient. One of the very useful built-in functions is the isinstance() function. This article will introduce the usage and examples of the isinstance function and provide specific code examples. The isinstance() function is used to determine whether an object is an instance of a specified class or type. The syntax of this function is as follows

Introduction to Python functions: functions and examples of eval function Introduction to Python functions: functions and examples of eval function Nov 04, 2023 pm 12:24 PM

Introduction to Python functions: functions and examples of the eval function In Python programming, the eval function is a very useful function. The eval function can execute a string as program code, and its function is very powerful. In this article, we will introduce the detailed functions of the eval function, as well as some usage examples. 1. Function of eval function The function of eval function is very simple. It can execute a string as Python code. This means that we can convert a string

See all articles