名词解释

粘包: 会将消息粘粘起来发送。类似吃米饭,一口吃多个饭粒,而不是一粒一粒的吃。

拆包: 会将消息拆开,分为多次接受。类似喝饮料,一口一口的喝,而不是一口气喝完。

简单的来说:

多次发送较少内容,会发生粘包现象。

单次发送内容过多,会发生拆包现象。

我们使用简单的Netty的服务端和客户端demo用来测试粘包和拆包。

将 Hello Netty 发送一百次,就会发送粘包现象;

将《春江花月夜》和《行路难》发送一次就会发送拆包现象;

示例图:

粘包:

拆包:

解决粘包、拆包

因为Netty已经提供了几个常用的解码器,帮助我们解决这些问题,所以我们不必再去造轮子了,直接拿来用就好了。

解决粘包

在Server服务端使用定长数据帧的解码器 FixedLengthFrameDecoder 之后。

可以明显看到数据已经按照我们所设定的大小分割了。

解决拆包

在Server服务端使用字节解码器 LineBasedFrameDecoder 之后。

由于字节已经超过我们设置的最大的字节数,所以报错了。

所以,我们发送的字节在设置的范围内的话,就可以看到拆包现象已经解决。

Netty还提供了一个 HttpObjectAggregator 类用于解决粘包、拆包现象。

以下摘自Netty官方文档

如果对于单条HTTP消息你不想处理多个消息对象,你可以传入 HttpObjectAggregator 到pipline中。HttpObjectAggregator 会将多个消息对象转变为单个 FullHttpRequest 或者 FullHttpResponse。

使用 HttpObjectAggregator 之后

可以看到,粘包和拆包现象得到了改善。

那么开始贴代码,几乎和之前的demo一样。

服务端:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;/***
* Title: NettyServer
* Description: Netty服务端
* Version:1.0.0
* @author pancm
* @date 2017年10月8日*/
public class NettyServer {private static final int port = 6789; //设置服务端端口private static  EventLoopGroup group = new NioEventLoopGroup();   // 通过nio方式来接收连接和处理连接   private static  ServerBootstrap b = new ServerBootstrap();/*** Netty创建全部都是实现自AbstractBootstrap。* 客户端的是Bootstrap,服务端的则是  ServerBootstrap。**/public static void main(String[] args) throws InterruptedException {try {b.group(group);b.channel(NioServerSocketChannel.class);b.childHandler(new NettyServerFilter()); //设置过滤器// 服务器绑定端口监听ChannelFuture f = b.bind(port).sync();System.out.println("服务端启动成功,端口是:"+port);// 监听服务器关闭监听f.channel().closeFuture().sync();}catch(Exception e){e.printStackTrace();}finally {group.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程  }}
}
mport io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;/*** * Title: HelloServerInitializer* Description: Netty 服务端过滤器* Version:1.0.0
* @author pancm
* @date 2017年10月8日*/
public class NettyServerFilter extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline ph = ch.pipeline();// 解码和编码,应和客户端一致
//       ph.addLast(new FixedLengthFrameDecoder(100));   //定长数据帧的解码器 ,每帧数据100个字节就切分一次。  用于解决粘包问题
//         ph.addLast(new LineBasedFrameDecoder(2048));     //字节解码器 ,其中2048是规定一行数据最大的字节数。  用于解决拆包问题ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024)); ph.addLast("decoder", new StringDecoder());ph.addLast("encoder", new StringEncoder());ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑}}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;import java.net.InetAddress;/***
* Title: HelloServerHandler
* Description:  服务端业务逻辑 粘包、拆包测试
* Version:1.0.0
* @author pancm
* @date 2017年10月8日*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {/** 条数 */private int count=0; /*** 业务逻辑处理*/@Override  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  String body = (String)msg;  System.out.println("接受的数据是: " + body + ";条数是: " + ++count); }  /*** 建立连接时,返回消息*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");super.channelActive(ctx);}
}

客户端

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;import java.io.IOException;
/***
* Title: NettyClient
* Description: Netty客户端  粘包、拆包测试
* Version:1.0.0
* @author pancm
* @date 2017年10月16日*/
public class NettyClient {public static String host = "127.0.0.1";  //ip地址public static int port = 6789;            //端口/// 通过nio方式来接收连接和处理连接   private static EventLoopGroup group = new NioEventLoopGroup(); private static  Bootstrap b = new Bootstrap();private static Channel ch;/*** Netty创建全部都是实现自AbstractBootstrap。* 客户端的是Bootstrap,服务端的则是    ServerBootstrap。**/public static void main(String[] args) throws InterruptedException, IOException { System.out.println("客户端成功启动...");b.group(group);b.channel(NioSocketChannel.class);b.handler(new NettyClientFilter()); // 连接服务端ch = b.connect(host, port).sync().channel();star(3);}public static void star(int i) throws IOException{String str="春江潮水连海平,海上明月共潮生。"+"  滟滟随波千万里,何处春江无月明! "+"    江流宛转绕芳甸,月照花林皆似霰;"+"   空里流霜不觉飞,汀上白沙看不见。"+"   江天一色无纤尘,皎皎空中孤月轮。"+"  江畔何人初见月?江月何年初照人?"+" 人生代代无穷已,江月年年望相似。"+"   不知江月待何人,但见长江送流水。"+"   白云一片去悠悠,青枫浦上不胜愁。"+"   谁家今夜扁舟子?何处相思明月楼?"+"    可怜楼上月徘徊,应照离人妆镜台。"+"   玉户帘中卷不去,捣衣砧上拂还来。"+"   此时相望不相闻,愿逐月华流照君。"+"   鸿雁长飞光不度,鱼龙潜跃水成文。"+"   昨夜闲潭梦落花,可怜春半不还家。"+"   江水流春去欲尽,江潭落月复西斜。"+"   斜月沉沉藏海雾,碣石潇湘无限路。"+"   不知乘月几人归,落月摇情满江树。" +" 噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。"+" 西当太白有鸟道,可以横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。上有六龙回日之高标,下有冲波逆折之回川。"+" 黄鹤之飞尚不得过,猿猱欲度愁攀援。青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。"+" 问君西游何时还?畏途巉岩不可攀。但见悲鸟号古木,雄飞雌从绕林间。又闻子规啼夜月,愁空山。"+" 蜀道之难,难于上青天,使人听此凋朱颜!连峰去天不盈尺,枯松倒挂倚绝壁。飞湍瀑流争喧豗,砯崖转石万壑雷。"+" 其险也如此,嗟尔远道之人胡为乎来哉!剑阁峥嵘而崔嵬,一夫当关,万夫莫开。"+" 所守或匪亲,化为狼与豺。朝避猛虎,夕避长蛇;磨牙吮血,杀人如麻。锦城虽云乐,不如早还家。"+" 蜀道之难,难于上青天,侧身西望长咨嗟!";if(i==1){for(int j=0;j<100;j++){str="Hello Netty";ch.writeAndFlush(str);}}else if(i==2){str+=str;ch.writeAndFlush(str);}else if(i==3){//System.getProperty("line.separator") 结束标记byte [] bt=(str+System.getProperty("line.separator")).getBytes();ByteBuf message = Unpooled.buffer(bt.length);  message.writeBytes(bt);  ch.writeAndFlush(message);}System.out.println("客户端发送数据:"+str+",发送数据的长度:"+str.length());}}
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/***
* Title: NettyClientFilter
* Description: Netty客户端 过滤器
* Version:1.0.0
* @author pancm
* @date 2017年10月8日*/
public class NettyClientFilter extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline ph = ch.pipeline();/** 解码和编码,应和服务端一致* */ph.addLast("decoder", new StringDecoder());ph.addLast("encoder", new StringEncoder());ph.addLast("handler", new NettyClientHandler()); //客户端的逻辑}
}
import java.util.Date;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;/***
* Title: NettyClientHandler
* Description: 客户端业务逻辑实现
* Version:1.0.0
* @author pancm
* @date 2017年10月8日*/
public class NettyClientHandler extends ChannelInboundHandlerAdapter {/*** 业务逻辑处理   */@Override  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  System.out.println("客户端接受的消息:"+msg);}  /*** 建立连接时*/@Override  public void channelActive(ChannelHandlerContext ctx) throws Exception {  System.out.println("建立连接时:"+new Date());  ctx.fireChannelActive();  }  /*** * 关闭连接时*/@Override  public void channelInactive(ChannelHandlerContext ctx) throws Exception {  System.out.println("关闭连接时:"+new Date());  }
}

Netty4 学习笔记之三-粘包和拆包相关推荐

  1. Netty 框架学习(二):Netty粘包和拆包

    文章目录 一.什么是粘包和拆包 二.粘包和拆包示例代码 1.TimeServerHandler 2.TimeClientHandler 三.使用Netty解决粘包和拆包 1.TimeServerHan ...

  2. linux系统管理学习笔记之三----软件的安装

    linux系统管理学习笔记之三----软件的安装 2009-12-29 19:10:02 标签:linux 系统管理 [推送到技术圈] 版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 ...

  3. 面试官问:你来讲下Netty通信中的粘包、拆包?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Java技术剑 来源:https://urlify.cn/I ...

  4. Netty 解决粘包和拆包问题的四种方案

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | https://my.oschina.net/ ...

  5. 【Netty】TCP粘包和拆包

    一.前言 前面已经基本上讲解完了Netty的主要内容,现在来学习Netty中的一些可能存在的问题,如TCP粘包和拆包. 二.粘包和拆包 对于TCP协议而言,当底层发送消息和接受消息时,都需要考虑TCP ...

  6. 面试题:聊聊TCP的粘包、拆包以及解决方案

    TCP的粘包和拆包问题往往出现在基于TCP协议的通讯中,比如RPC框架.Netty等.如果你的简历中写了类似的技术或者你所面试的公司使用了相关的技术,被问到该面试的几率会非常高. 今天这篇文章就带大家 ...

  7. 【Netty】Netty解决粘包和拆包问题的四种方案

    在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接.由于微服务往对方发送信息的时候,所有的请求都是使 ...

  8. Netty解决粘包和拆包问题的四种方案

    在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接.由于微服务往对方发送信息的时候,所有的请求都是使 ...

  9. TCP的粘包和拆包及Netty中的解决方案

    1.基本介绍 TCP 是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的 socket, 因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(N ...

最新文章

  1. Ubuntu14.04 64位机上安装OpenCV2.4.13(CUDA8.0)版操作步骤
  2. 30分钟正则表达式入门。
  3. Go 读取 yaml 文件并解析
  4. 一种新的Heap区溢出技术分析[转贴]
  5. att格式汇编指令_ARM汇编伪指令介绍.
  6. 巧用linux版powershell,管理linux下的docker
  7. imos style android,自定义的第一个view
  8. 在C#中从Keras.NET开始——训练您的第一个模型
  9. 设计模式在游戏中的应用--模板方法(七)
  10. 搭建第一个springBoot 摘抄自蚂蚁课堂
  11. 186.MultiAutoCompleteTextView
  12. ARCGIS近邻分析应用详解
  13. 以大TMS运输配送管理系统
  14. 视频转文字怎么操作?快把这些方法收好
  15. 301、404、200、304等HTTP状态
  16. Linux 历史简介
  17. c++屏蔽Win10系统快捷键
  18. css中设置交叉轴内容为拉伸,CSS-弹性布局2-交叉轴
  19. linux 命令的英文缩写含义----文件夹英文缩写的含义
  20. 新书介绍 -- 《Redis核心原理与实践》

热门文章

  1. Java游戏服务器架构的并发问题及解决方案
  2. 微信公众号:设置分享
  3. 京东月薪8万快递员:真正牛逼的人,都拥有这个特质
  4. c语言还是python-自学编程应该从c语言还是python入手?
  5. WEKA算法开发——记一次不太成功的遗传属性加权贝叶斯算法实验
  6. Android Studio 选项菜单和动画结合_安卓手机关于“开发者选项”你该知道的几件事...
  7. 陷阱技术探秘 ----动态汉化Windows技术的分析
  8. 题目 2281: 次数差
  9. 龟兔赛跑预测 【简单模拟】
  10. Karabiner Elements for Mac(键盘改键神器)