<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: xilio</title>
    <description>The latest articles on DEV Community by xilio (@xilio).</description>
    <link>https://dev.to/xilio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3253714%2Ff01ceb87-4c55-4de0-9f9d-eb467ff619e9.JPG</url>
      <title>DEV Community: xilio</title>
      <link>https://dev.to/xilio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xilio"/>
    <language>en</language>
    <item>
      <title>【最新】基于Netty实现的开源免费 内网穿透神器vin，即装即用，再也不用花大钱了，安全高效多客户端多协议穿透</title>
      <dc:creator>xilio</dc:creator>
      <pubDate>Sun, 22 Jun 2025 14:01:20 +0000</pubDate>
      <link>https://dev.to/xilio/zui-xin-ji-yu-nettyshi-xian-de-kai-yuan-mian-fei-nei-wang-chuan-tou-shen-qi-vineji-zhuang-ji-yong-zai-ye-bu-yong-hua-da-qian-liao-an-quan-gao-xiao-duo-ke-hu-duan-duo-xie-yi-chuan-tou-1j1k</link>
      <guid>https://dev.to/xilio/zui-xin-ji-yu-nettyshi-xian-de-kai-yuan-mian-fei-nei-wang-chuan-tou-shen-qi-vineji-zhuang-ji-yong-zai-ye-bu-yong-hua-da-qian-liao-an-quan-gao-xiao-duo-ke-hu-duan-duo-xie-yi-chuan-tou-1j1k</guid>
      <description>&lt;h2&gt;
  
  
  介绍
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;内网穿透&lt;/strong&gt; 主要用于将内网的服务，例如&lt;strong&gt;MySQL&lt;/strong&gt;、&lt;strong&gt;Redis&lt;/strong&gt;、&lt;strong&gt;Tomcat&lt;/strong&gt;等服务暴露到公网，解决服务器内存严重不足且费用高的问题，这在系统测试时非常有用。市面上有一些三方的代理如&lt;strong&gt;花生壳&lt;/strong&gt;，不仅&lt;strong&gt;价格昂贵&lt;/strong&gt;，而且还存在&lt;strong&gt;数据泄漏风险&lt;/strong&gt;（最主要还是太贵😄）。&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2qwg1rgj5fqq3l9yhfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2qwg1rgj5fqq3l9yhfl.png" alt="在这里插入图片描述" width="601" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vine&lt;/strong&gt;是一个基于Java生态的内网穿透工具（类似于Go语言实现的frp），目前版本支持TCP/HTTP协议穿透。&lt;/p&gt;

&lt;p&gt;🔥Github开源地址：&lt;a href="https://github.com/xilio-dev/vine" rel="noopener noreferrer"&gt;https://github.com/xilio-dev/vine&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;## Github截图&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsq933qkvkolgi6s5hs7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsq933qkvkolgi6s5hs7.png" alt="在这里插入图片描述" width="800" height="457"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdajajqz8fsyokpzlr4if.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdajajqz8fsyokpzlr4if.png" alt="在这里插入图片描述" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuavhs7riuop6juwtcz0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuavhs7riuop6juwtcz0e.png" alt="在这里插入图片描述" width="800" height="716"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;更多细节访问&lt;strong&gt;Github&lt;/strong&gt;： &lt;a href="https://github.com/xilio-dev/vine" rel="noopener noreferrer"&gt;https://github.com/xilio-dev/vine&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb9jucvidkzx15hqpyib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb9jucvidkzx15hqpyib.png" alt="在这里插入图片描述" width="285" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>netty</category>
      <category>vine</category>
    </item>
    <item>
      <title>Bug：io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1</title>
      <dc:creator>xilio</dc:creator>
      <pubDate>Sat, 21 Jun 2025 03:04:56 +0000</pubDate>
      <link>https://dev.to/xilio/bugionettyutilillegalreferencecountexception-refcnt-0-decrement-1-1i2g</link>
      <guid>https://dev.to/xilio/bugionettyutilillegalreferencecountexception-refcnt-0-decrement-1-1i2g</guid>
      <description>&lt;p&gt;我在使用netty做项目的时候发生了错误，错误堆栈信息如下：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt&lt;span class="o"&gt;(&lt;/span&gt;ReferenceCountUpdater.java:83&lt;span class="o"&gt;)&lt;/span&gt;
    at io.netty.util.internal.ReferenceCountUpdater.release&lt;span class="o"&gt;(&lt;/span&gt;ReferenceCountUpdater.java:148&lt;span class="o"&gt;)&lt;/span&gt;
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release&lt;span class="o"&gt;(&lt;/span&gt;AbstractReferenceCountedByteBuf.java:101&lt;span class="o"&gt;)&lt;/span&gt;
    at io.netty.util.ReferenceCountUtil.release&lt;span class="o"&gt;(&lt;/span&gt;ReferenceCountUtil.java:90&lt;span class="o"&gt;)&lt;/span&gt;
    at io.netty.channel.SimpleChannelInboundHandler.channelRead&lt;span class="o"&gt;(&lt;/span&gt;SimpleChannelInboundHandler.java:106&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  原因分析
&lt;/h2&gt;

&lt;p&gt;发生错误的原因是重复释放ByteBuf缓冲区，我在处理器中手动调用了release释放buf，然而该buf是由netty底层进行管理的，会被再次调用，所以出现了该错误！&lt;/p&gt;

&lt;h2&gt;
  
  
  解决方案
&lt;/h2&gt;

&lt;p&gt;删除&lt;code&gt;ReferenceCountUtil.release(buf)&lt;/code&gt;该行代码。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;channelRead0&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChannelHandlerContext&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ByteBuf&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;//ReferenceCountUtil.release(buf);//删除该行代码，buf由netty底层进行管理&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;     

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>netty</category>
      <category>bug</category>
    </item>
    <item>
      <title>Gitee隐私保护机制导致无法push解决方案</title>
      <dc:creator>xilio</dc:creator>
      <pubDate>Sun, 15 Jun 2025 03:26:06 +0000</pubDate>
      <link>https://dev.to/xilio/giteeyin-si-bao-hu-ji-zhi-dao-zhi-wu-fa-pushjie-jue-fang-an-la6</link>
      <guid>https://dev.to/xilio/giteeyin-si-bao-hu-ji-zhi-dao-zhi-wu-fa-pushjie-jue-fang-an-la6</guid>
      <description>&lt;p&gt;问题是由于 ​​Gitee 的&lt;strong&gt;邮箱隐私保护机制​​&lt;/strong&gt;阻止了推送，因为提交中包含 ​隐藏的邮箱地址​​。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
11:17:19.414: [xilio-doc] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false push --progress --porcelain origin refs/heads/main:main
11:17:40.485: [xilio-doc] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false fetch origin --recurse-submodules=no --progress --prune
11:17:58.256: [xilio-doc] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false push --progress --porcelain gitee refs/heads/main:main
Enumerating objects: 12, done.
Counting objects:   8% (1/12)
Counting objects:  16% (2/12)
Counting objects:  25% (3/12)
Counting objects:  33% (4/12)
Counting objects:  41% (5/12)
Counting objects:  50% (6/12)
Counting objects:  58% (7/12)
Counting objects:  66% (8/12)
Counting objects:  75% (9/12)
Counting objects:  83% (10/12)
Counting objects:  91% (11/12)
Counting objects: 100% (12/12)
Counting objects: 100% (12/12), done.
Delta compression using up to 8 threads
Compressing objects:  14% (1/7)
Compressing objects:  28% (2/7)
Compressing objects:  42% (3/7)
Compressing objects:  57% (4/7)
Compressing objects:  71% (5/7)
Compressing objects:  85% (6/7)
Compressing objects: 100% (7/7)
Compressing objects: 100% (7/7), done.
Writing objects:  14% (1/7)
Writing objects:  28% (2/7)
Writing objects:  42% (3/7)
Writing objects:  57% (4/7)
Writing objects:  71% (5/7)
Writing objects:  85% (6/7)
Writing objects: 100% (7/7)
Writing objects: 100% (7/7), 53.60 KiB | 17.87 MiB/s, done.
Total 7 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [1.1.5]        
remote: Set trace flag 0a432682        
remote: Push will publish a hidden email, make email public or abandon related commits        
remote: error: hook declined to update refs/heads/main        
error: failed to push some refs to 'gitee.com:xilio/xilio-doc.git'
To gitee.com:xilio/xilio-doc.git
!   refs/heads/main:refs/heads/main [remote rejected] (hook declined)
Done

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;解决方案：公开邮箱&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw0n2uejgeedss63oy0z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw0n2uejgeedss63oy0z.png" alt=" " width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gitee</category>
    </item>
    <item>
      <title>图文讲解Netty编解码器解决沾包和半包问题，透析本质</title>
      <dc:creator>xilio</dc:creator>
      <pubDate>Sun, 15 Jun 2025 03:11:18 +0000</pubDate>
      <link>https://dev.to/xilio/tu-wen-jiang-jie-bian-jie-ma-qi-jie-jue-zhan-bao-he-ban-bao-wen-ti-tou-xi-ben-zhi-36pc</link>
      <guid>https://dev.to/xilio/tu-wen-jiang-jie-bian-jie-ma-qi-jie-jue-zhan-bao-he-ban-bao-wen-ti-tou-xi-ben-zhi-36pc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanotx8q9j96xoxncmt2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanotx8q9j96xoxncmt2h.png" alt=" " width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TCP是以流的方式进行字节传输的，所以无法知道数据的边界，也就意味着无法区分出一串数据，比如一段二进制由于没有边界，客户端收到以后随意截取就会导致数据错乱，不是期望收到的数据。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;下面一段代码是一个基本的解码器的案例：&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomDecoder&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ByteToMessageDecoder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChannelHandlerContext&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ByteBuf&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readableBytes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 检查是否有足够的字节读取长度字段 【1】&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readInt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 读取4字节的长度字段 【2】&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readableBytes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;//【3】&lt;/span&gt;
            &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resetReaderIndex&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 数据不足，重置读取位置 【4】&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;ByteBuf&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 读取消息体【5】&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 输出到下游 【6】&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;代码详解：&lt;/p&gt;

&lt;p&gt;【1】&lt;code&gt;in.readableBytes() &amp;lt; 4&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这段代码的效果是从TCP流中读取4个字节（想象从TCP流的最开始位置），这4个字节是用来记录后面Body数据的长度的，这样就可以确定后面数据的边界，确定后面的数据边界以后，通过偏移量就可以得到下一个Head，通过Head又可以得到后面Body的长度，&lt;br&gt;
以此类推，这样一来字节流就形成了边界，就可以组装成正确的数据了；那为什么是4而不是其他的呢？其实也可以是其他的（比如2、8字节等），因为4字节可以记录的长度在java中是32位，已经可以得到足够大的整数了，几乎可以满足所有的场景，这也是一个折中的选择&lt;br&gt;
如果用2字节表示的长度又太小，后面的Body内容实际可能很长，如果用8字节，那可能没必要，因为后面的Body大多数场景实际的数据没有那么长，如果用8的话就会造成浪费，完全没必要，所以这就是为什么要用4的原因。&lt;/p&gt;

&lt;p&gt;【2】&lt;code&gt;in.readInt()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这段代码的效果是读取4字节（我们规定的是4字节表示头），可以读取到一个整数表示后面Body的长度，连续读取该长度就可以得到一个正常的数据。&lt;/p&gt;

&lt;p&gt;【3】&lt;code&gt;in.readableBytes() &amp;lt; length&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;通过Head头我们知道后面Body应该读取多少长度的数据，但是由于TCP基于流的，可能会将一个很长的消息进行拆分传输，导致没有收到完整的的数据，也就是常常说的半包问题，&lt;br&gt;
因此需要做一个判断，等下次数据满足Head要读取的长度后再读取。&lt;/p&gt;

&lt;p&gt;【4】&lt;code&gt;in.resetReaderIndex()&lt;/code&gt;&lt;br&gt;
将索引恢复到上次的位置，不然下次读取就会错乱，原因在于调用&lt;code&gt;in.readableBytes()&lt;/code&gt;会导致索引先后移动，竟然这次都没有读取成功，肯定要恢复。&lt;/p&gt;

&lt;p&gt;【5】&lt;code&gt;in.readBytes(length)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;终于可以读取指定长度（来自Head）的字节数量了，得到的就是实际的Body内容，也就是发送者单次实际发送的数据。&lt;/p&gt;

</description>
      <category>netty</category>
      <category>java</category>
      <category>沾包</category>
    </item>
    <item>
      <title>TCP协议和UDP协议有什么区别？</title>
      <dc:creator>xilio</dc:creator>
      <pubDate>Tue, 10 Jun 2025 12:16:57 +0000</pubDate>
      <link>https://dev.to/xilio/tcpxie-yi-he-udpxie-yi-you-shi-yao-qu-bie--1ein</link>
      <guid>https://dev.to/xilio/tcpxie-yi-he-udpxie-yi-you-shi-yao-qu-bie--1ein</guid>
      <description>&lt;ul&gt;
&lt;li&gt;TCP协议是流式协议，基于字节流传输，没有数据的边界需要在应用层解决&lt;strong&gt;粘包&lt;/strong&gt;和&lt;strong&gt;半包&lt;/strong&gt;的问题，而UDP协议是基于&lt;strong&gt;数据报&lt;/strong&gt;传输的，有明确的数据边界。&lt;/li&gt;
&lt;li&gt;UDP是无序传输，不保证数据包的顺序，可能会出现丢包和乱序的情况，同时属于&lt;strong&gt;无连接&lt;/strong&gt;协议，不具备可靠性，TCP则相反。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;基于TCP的上层协议如HTTP/HTTPS、WebSocket、MQTT等协议都有各自的消息边界，所以在使用这些协议的时候，开发者不需要解决粘包和半包的问题。&lt;/p&gt;

</description>
      <category>networking</category>
      <category>http</category>
      <category>mqtt</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
