Netty中最简单的粘包解析方法分享

 更新时间:2023年05月16日 14:55:52   作者:宁轩  
黏包 是指网络上有多条数据发送给服务端, 但是由于某种原因这些数据在被接受的时候进行了重新组合,本文分享了一种最简单的黏包解析方法, 非常适用于初初初级选手

前言

黏包 是指网络上有多条数据发送给服务端, 但是由于某种原因这些数据在被接受的时候进行了重新组合, 这就是黏包, 本篇文章用来演示一种最简单的黏包解析方法, 适用于初初初级选手

正常来讲客户端发送给服务端的消息, 都是存在专门的通讯协议的, 为了避免黏包现象, 我们通常有几种方式去制定相应的规则: 消息长度固定, 特定分隔符, 消息长度固定+特定分隔符

本文是采用了 特定分隔符 的方式, 每条数据包都以 \n 结尾

例如以下三条原始数据数据:

hell\n
ningxuan\n
thanks\n

变成了以下两个:

hello\nningxuan\nth
anks\n

这就是黏包

黏包产生的原因

socket 网络编程中, TCPUDP 分别是面向连接和非面相连接的. 但是他们都存在产生黏包问题吗?

本文不会对 tcp 和 udp 进行详细的讲解, 感兴趣的可以自行百度或者掘金

tcp

先说结论: tcp 会产生黏包问题

由于 tcp 协议本身的机制(面向连接的可靠性协议-三次握手机制) 客户端与服务端会维持一个连接(Channel), 数据在连接不断开的情况下, 可以将多个数据包持续不断的发送到服务器上.

但是如果发送的网络数据包太小, tcp就会启用Nagle算法对多个数据包进行合并再发送到服务器上. 这种情况下服务器在接收到消息的时候无法区分哪些数据包是分开的, 所以产生了黏包

还有一种可能是: 服务器在接收到数据之后, 将数据放入到缓冲区中, 如果消息没有被及时的从缓冲区取走, 下次在取数据的时候就会出现一次取到多个数据包的情况, 造成黏包现象

tcp三次握手:

  • 客户端服务端发送建立通道请求
  • 服务端客户端发送允许客户端建立一个单向的数据通道; 服务端向客户端发送建立通道请求
  • 客户端服务端发送允许服务端建立一个单向的数据通道

此时数据通道是双向的, 允许客户端、服务端互相发送消息

Nagle算法:

  • 如果包长度达到 MSS, 则允许发送
  • 如果该包中含有 FIN, 则允许发送
  • 设置了 TCP_NODELAY 选项, 若所有发出去的小数据包(长度小于 MSS )均被确认, 则允许发送
  • 若上述条件均未满足, 但发送了超时(一般为 200ms ), 则立即发送

udp

upd 不存在黏包问题

udp本身是无连接的不可靠传输协议, 不会对数据包进行合并发送, 也就没有Nagle算法, 不会存在数据合并的情况, 每一个数据包都是完整的, 所以不存在黏包现象

最简单的黏包解析

黏包解析也很简单:

  • 遍历当前的 ByteBuffer 缓冲区
  • 判断元素为 '\n' 的下标
  • 生成新的 ByteBuffer 缓冲区
  • 将起始下标到标记下标的字符写到新的缓冲区

具体代码如下所示:

public class ByteBufferTest {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.put("hello\nningxuan\nth".getBytes());
        split(buffer);
        buffer.put("anks\n".getBytes());
        split(buffer);
    }

    private static void split(ByteBuffer buffer){
        // 将 buffer 切换为 读模式
        buffer.flip();
        // 根据 buffer 当前的长度进行遍历
        for (int i = 0; i < buffer.limit(); i++) {
            // 判断当前下标元素是不是数据包切割符 \n
            if (buffer.get(i) == '\n'){ // 注意这个时候 buffer 的 position 属性一直为 0
                // 计算当前数据包长度
                int length = i + 1 - buffer.position();
                // 根据当前数据包长度, 动态生成新的 缓冲区
                ByteBuffer target = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    target.put(buffer.get());   // 注意这个时候 buffer 的 position 属性在 ++
                }
                // 打印 target 当前的元素和属性
                ByteBufferUtils.selectAll(target);
            }
        }
        buffer.compact();
    }
}

到此这篇关于Netty中最简单的粘包解析方法分享的文章就介绍到这了,更多相关粘包解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中守护线程介绍及使用

    Java中守护线程介绍及使用

    大家好,本篇文章主要讲的是Java中守护线程介绍及使用,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • javaweb实现文件上传功能

    javaweb实现文件上传功能

    这篇文章主要为大家详细介绍了javaweb实现文件上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • java Comparator.comparing排序使用示例

    java Comparator.comparing排序使用示例

    本文主要介绍了java Comparator.comparing排序使用示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • Redis如何实现分布式锁详解

    Redis如何实现分布式锁详解

    分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁.本篇文章将介绍第二种方式,基于Redis实现分布式锁,文中有非常详细的介绍,需要的朋友可以参考下
    2021-06-06
  • mybatis自动生成@Table、@Column、@Id注解的方法

    mybatis自动生成@Table、@Column、@Id注解的方法

    这篇文章主要介绍了mybatis自动生成@Table、@Column、@Id注解的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Spring Boot 整合持久层之MyBatis

    Spring Boot 整合持久层之MyBatis

    在实际开发中不仅仅是要展示数据,还要构成数据模型添加数据,这篇文章主要介绍了SpringBoot集成Mybatis操作数据库,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Spring boot连接MySQL 8.0可能出现的问题

    Spring boot连接MySQL 8.0可能出现的问题

    这篇文章主要给大家介绍了关于Spring boot连接MySQL 8.0可能出现的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-10-10
  • Java String类的理解及字符串常量池介绍

    Java String类的理解及字符串常量池介绍

    这篇文章主要介绍了Java String类的理解及字符串常量池介绍,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • @PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter注解的用法详解

    @PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter注解的用法详解

    这篇文章主要介绍了@PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter注解的用法详解,通过在方法上添加@PreAuthorize注解,可以指定需要满足的权限条件,只有满足条件的用户才能执行该方法,需要的朋友可以参考下
    2023-10-10
  • spring-data-jpa实现增删改查以及分页操作方法

    spring-data-jpa实现增删改查以及分页操作方法

    下面小编就为大家分享一篇spring-data-jpa实现增删改查以及分页操作方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02

最新评论