TCP粘包拆包及NETTY解决方案

2023-11-06 02:40

本文主要是介绍TCP粘包拆包及NETTY解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第一个netty应用

pom

<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.16.Final</version>
</dependency>

EchoServer

package com.aegis.netty.demo1;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class EchoServer {public static void main(String[] args) throws Exception{//创建boss和worker线程(1)EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();//服务端是ServerBootstrapServerBootstrap b = new ServerBootstrap();//初始化boss和work线程化两个线程(3)b.group(bossGroup, workerGroup)//声明NioServerSocketChannel(4).channel(NioServerSocketChannel.class)//初始化客户端Handler(5).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) {ch.pipeline().addLast(new EchoServerHandler());}});//绑定端口(6)ChannelFuture f = b.bind(8888).sync();f.channel().closeFuture().sync();}
}

EchoServerHandler

package com.aegis.netty.demo1;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;public class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf in = (ByteBuf) msg;System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));}
}

EchoClient

package com.aegis.netty.demo1;import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;public class EchoClient {public static void main(String[] args) throws Exception{EventLoopGroup group = new NioEventLoopGroup();//客户端是BootstrapBootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress("localhost", 8888)).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch)throws Exception {ch.pipeline().addLast(new EchoClientHandler());}});ChannelFuture future = b.connect().sync();Channel channel = future.channel();channel.writeAndFlush(Unpooled.copiedBuffer(("客户端第1条消息" + channel.remoteAddress()).getBytes()));channel.writeAndFlush(Unpooled.copiedBuffer("客户端第2条消息".getBytes()));channel.writeAndFlush(Unpooled.copiedBuffer("客户端第3条消息".getBytes()));channel.closeFuture().sync();    }
}

EchoClientHandler

package com.aegis.netty.demo1;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;public class EchoClientHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {//System.out.println("客户端收到消息:[" + msg + "]");ByteBuf in = (ByteBuf) msg;System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));}
}

tcp拆包粘包

现象

上述代码客户端连上服务端后,发了三条消息分别是:客户端第1条localhost/127.0.0.1:8888 、客户端第2条消息、客户端第3条消息.服务端的逻辑是每次收到一条消息就打印出来,并给服务端回复三条消息我是服务端、我是服务端、我是服务端。所以服务端会收到3条消息,并给客户端返回9条消息,客户端能收到9条消息。但是由于TCP 粘包拆包原因,结果往往出乎意料

  1. 服务端收到3条消息,客户端收到6条消息

  1. 服务端收到3条消息,客户端收到一条消息

3、客户端服务端都收到一条消息

。。。。。各种可能

原因

抓包

wireshark

【最详细】Wireshark使用教程_未名编程的博客-CSDN博客_wireshark使用教程入门

代码中的消息改成了英文,方便展示,下面是抓到的包

0000 02 00 00 00 45 00 00 51 22 06 40 00 80 06 00 00 ....E..Q".@.....

0010 7f 00 00 01 7f 00 00 01 d0 06 22 b8 6b d7 1e ab ..........".k...

0020 bb 04 71 8f 50 18 08 05 95 64 00 00 63 6c 69 65 ..q.P....d..clie

0030 6e 74 20 31 20 6d 65 73 73 61 67 65 6c 6f 63 61 nt 1 messageloca

0040 6c 68 6f 73 74 2f 31 32 37 2e 30 2e 30 2e 31 3a lhost/127.0.0.1:

0050 38 38 38 38 24 8888$

0000 02 00 00 00 45 00 00 39 22 14 40 00 80 06 00 00 ....E..9".@.....

0010 7f 00 00 01 7f 00 00 01 d0 06 22 b8 6b d7 1e d4 ..........".k...

0020 bb 04 71 8f 50 18 08 05 1f 96 00 00 63 6c 69 65 ..q.P.......clie

0030 6e 74 20 32 20 6d 65 73 73 61 67 65 24 nt 2 message$

0000 02 00 00 00 45 00 00 39 22 18 40 00 80 06 00 00 ....E..9".@.....

0010 7f 00 00 01 7f 00 00 01 d0 06 22 b8 6b d7 1e e5 ..........".k...

0020 bb 04 71 8f 50 18 08 05 1f 84 00 00 63 6c 69 65 ..q.P.......clie

0030 6e 74 20 33 20 6d 65 73 73 61 67 65 24 nt 3 message$

下面是服务端收到的包,也就是channelRead中ByteBuf 16进制打印结果

 

63 6c 69 65 6e 74 20 31 20 6d 65 73 73 61 67 65 6c 6f 63 61 6c 68 6f 73 74 2f 31 32 37 2e 30 2e 30 2e 31 3a 38 38 38 38 24 63 6c 69 65 6e 74 20 32 20 6d 65 73 73 61 67 65 24 63 6c 69 65 6e 74 20 33 20 6d 65 73 73 61 67 65 24

netty解决tcp 粘包拆包方案

  1. 定长FixedLengthFrameDecoder

  2. 特殊字符切割DelimiterBasedFrameDecoder

下面以$符号作为切割符,分别在客户端和服务端添加DelimiterBasedFrameDecoder。发送的消息末尾加上$

ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
channel.writeAndFlush(Unpooled.copiedBuffer("客户端第2条消息$".getBytes()));

结果如下:服务端收到3条消息,客户端收到9条消息

        3.自定义协议实现文件的上传下载(后面介绍)

这篇关于TCP粘包拆包及NETTY解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/354008

相关文章

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

使用DrissionPage控制360浏览器的完美解决方案

《使用DrissionPage控制360浏览器的完美解决方案》在网页自动化领域,经常遇到需要保持登录状态、保留Cookie等场景,今天要分享的方案可以完美解决这个问题:使用DrissionPage直接... 目录完整代码引言为什么要使用已有用户数据?核心代码实现1. 导入必要模块2. 关键配置(重点!)3.

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR

Seata之分布式事务问题及解决方案

《Seata之分布式事务问题及解决方案》:本文主要介绍Seata之分布式事务问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Seata–分布式事务解决方案简介同类产品对比环境搭建1.微服务2.SQL3.seata-server4.微服务配置事务模式1