netty 粘包的解决策略
粘包问题的解决策略
- 消息定长, 例如每个报文的大小固定长度200字节,如果不够,空位补齐空格;
- 在包尾部添加回车换行符进行分割, 例如 FTP 协议;
- 将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息具体长度)的字段,通常设计思路为消息头的第一个字段使用 int32 来表示消息的总长度;
- 更复杂的应用协议层;
一. LineBasedFrameDecoder 与 StringDecoder
LineBasedFrameDecoder 与 StringDecoder 的工作原理
package time.server.impl; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder; /**
* TODO
*
* @description
* @author mjorcen
* @time 2015年5月25日 下午2:50:57
*/
public class NTimeServerImpl { public void bind(int port) {
// 创建两个NioEventLoopGroup 实例,NioEventLoopGroup
// 是一个线程组,它包含一组NIO线程,专门用于处理网络事件的处理,实际上他们就是Reactor 线程组
// 这里创建两个的原因是一个用于服务端接收用户的链接,另一个用于进行SocketChannel的网络读写
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
// 创建一个 ServerBootstrap ,它是netty用于NIO服务端的辅助启动类,目的是降低服务端的开发复杂度.
ServerBootstrap bootstrap = new ServerBootstrap();
// 设定 服务端接收用户请求的线程组和用于进行SocketChannel网络读写的线程组
bootstrap.group(bossGroup, workerGroup);
// 设置创建的 channel 类型
bootstrap.channel(NioServerSocketChannel.class);
// 配置 NioServerSocketChannel 的 tcp 参数, BACKLOG 的大小
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
// 绑定io处理类(childChannelHandler).他的作用类似于 reactor 模式中的 handler
// 类,主要用于处理网络 I/O 事件,例如对记录日志,对消息进行解码等.
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LineBasedFrameDecoder(1024)); // 加入行处理器
ch.pipeline().addLast(new StringDecoder()); // 加入字符串解码器
ch.pipeline().addLast(new TimeServerHandler());
}
});
// 绑定端口,随后调用它的同步阻塞方法 sync 等等绑定操作成功,完成之后 Netty 会返回一个 ChannelFuture
// 它的功能类似于的 Future,主要用于异步操作的通知回调.
ChannelFuture channelFuture = bootstrap.bind(port).sync();
// 等待服务端监听端口关闭,调用 sync 方法进行阻塞,等待服务端链路关闭之后 main 函数才退出.
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 优雅的退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} public static void main(String[] args) {
NTimeServerImpl server = new NTimeServerImpl();
server.bind(9091);
} }
ServerHandler
package time.server.impl; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import java.util.Date; import time.TimeConfig; /**
* TODO
*
* @description
* @author ez
* @time 2015年5月25日 下午3:06:09
*/
public class TimeServerHandler extends ChannelHandlerAdapter implements
TimeConfig { /*
* (non-Javadoc)
*
* @see io.netty.channel.ChannelHandlerAdapter#channelRead(io.netty.channel.
* ChannelHandlerContext, java.lang.Object)
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
String body = (String) msg;
System.out.println("The time server receive order : " + body);
String currentTime = QUERY.equalsIgnoreCase(body) ? new Date()
.toString() : "BAD ORDER";
currentTime += System.getProperty("line.separator");
System.out.println("currentTime : " + currentTime);
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes("utf-8"));
ctx.writeAndFlush(resp);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
// 当出现异常时,释放资源.
ctx.close();
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} }
Client
package time.client.impl; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder; /**
* TODO
*
* @description
* @author ez
* @time 2015年5月25日 下午3:17:29
*/
public class NTimeClient { public void connect(int port, String host) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try { Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new TimeClientHandler());
}
}); // 发起异步链接操作
ChannelFuture future = bootstrap.connect(host, port).sync(); // 等待客户端链路关闭
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
} public static void main(String[] args) throws Exception { NTimeClient client = new NTimeClient();
client.connect(9091, "localhost");
}
}
ClientHandler
package time.server.impl; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import java.util.Date; import time.TimeConfig; /**
* TODO
*
* @description
* @author ez
* @time 2015年5月25日 下午3:06:09
*/
public class TimeServerHandler extends ChannelHandlerAdapter implements
TimeConfig { /*
* (non-Javadoc)
*
* @see io.netty.channel.ChannelHandlerAdapter#channelRead(io.netty.channel.
* ChannelHandlerContext, java.lang.Object)
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
String body = (String) msg;
System.out.println("The time server receive order : " + body);
String currentTime = QUERY.equalsIgnoreCase(body) ? new Date()
.toString() : "BAD ORDER";
currentTime += System.getProperty("line.separator");
System.out.println("currentTime : " + currentTime);
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes("utf-8"));
ctx.writeAndFlush(resp);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
// 当出现异常时,释放资源.
ctx.close();
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} }
2: DelimiterBasedFrameDecoder
DelimiterBasedFrameDecoder 跟 LineBasedFrameDecoder 很相似 , 只是增加以自定义的分割符.
ByteBuf buf = Unpooled.copiedBuffer("$".getBytes("utf-8"));
ch.pipeline().addLast(
new DelimiterBasedFrameDecoder(1024, buf));
ch.pipeline().addLast(new FixedLengthFrameDecoder(1024));
netty 粘包的解决策略的更多相关文章
- netty 粘包问题处理
netty 粘包问题处理 key words: netty 粘包 解包 半包 TCP 一般TCP粘包/拆包解决办法 定长消息,例如每个报文长度固定,不够补空格 使用回车换行符分割,在包尾加上分割符,例 ...
- Netty 粘包/半包原理与拆包实战
Java NIO 粘包 拆包 (实战) - 史上最全解读 - 疯狂创客圈 - 博客园 https://www.cnblogs.com/crazymakercircle/p/9941658.html 本 ...
- Netty 粘包 拆包 | 史上最全解读
Netty 粘包/半包原理与拆包实战(史上最全) 疯狂创客圈 Java 聊天程序[ 亿级流量]实战系列之13 [博客园 总入口 ] 本文的源码工程:Netty 粘包/半包原理与拆包实战 源码 本实例是 ...
- tcp粘包、解决粘包问题
目录 subproess模块 TCP粘包问题 粘包两种情况 解决粘包问题 struct模块的使用 使用struct模块解决粘包 优化解决粘包问题 上传大文件 服务端 客户端 UDP协议 upd套接字 ...
- netty解决TCP的拆包和粘包的解决办法
TCP粘包.拆包问题 熟悉tcp编程的可能知道,无论是服务端还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP底层的粘包个拆包机制. tcp是一个“流”协议,所谓流就是没有界限的传输数据,在业 ...
- Netty 粘包/拆包应用案例及解决方案分析
熟悉TCP变成的可以知道,无论是客户端还是服务端,但我们读取或者发送消息的时候,都需要考虑TCP底层粘包/拆包机制,下面我们先看一下TCP 粘包/拆包和基础知识,然后模拟一个没有考虑TCP粘包/拆包导 ...
- Netty 粘包 & 拆包 & 编码 & 解码 & 序列化 介绍
目录: 粘包 & 拆包及解决方案 ByteToMessageDecoder 基于长度编解码器 基于分割符的编解码器 google 的 Protobuf 序列化介绍 其他的 前言 Netty 作 ...
- Netty - 粘包和半包(上)
在网络传输中,粘包和半包应该是最常出现的问题,作为 Java 中最常使用的 NIO 网络框架 Netty,它又是如何解决的呢?今天就让我们来看看. 定义 TCP 传输中,客户端发送数据,实际是把数据写 ...
- Netty粘包问题(六)
netty使用tcp/ip协议传输数据,而tcp/ip协议是类似水流一样的数据传输方法.多次访问的时候可能出现粘包的问题,解决这种问题的方式有如下几种. 一.定长数据流 二.特殊结束符 三.
随机推荐
- scrapy中间件
一.下载中间件 from scrapy import signals from scrapy.http import Response from scrapy.exceptions import Ig ...
- 编程菜鸟的日记-初学尝试编程-C++ Primer Plus 第4章编程练习2
#include <iostream>#include <string>int main(){ using namespace std; string name; string ...
- 为什么要DevOps?
Boss:「项目经常延期」「做东西太慢」 产品: 「老板的想法总变」 「事情太多,忙成狗」 「开发说这个实现不了」 开发: 「需求总变」 「UI 方案给的太晚」 「活儿太多」 测试: 「需求变了没提前 ...
- Sklearn线性回归
Sklearn线性回归 原理 线性回归是最为简单而经典的回归模型,用了最小二乘法的思想,用一个n-1维的超平面拟合n维数据 数学形式 \[y(w,x)=w_0+w_1x_1+w_2x_2+-+w_nx ...
- poj2456 Aggressive cows(二分查找)
https://vjudge.net/problem/POJ-2456 二分,从最大长度开始,不断折半试,如果牛全放下了,就是可行,修改下界,否则改上届. #include<iostream&g ...
- 5月25号开学! 第13期《python3自动化测试selenium+接口》课程,python零基础也能学
2019年 第13期<python3自动化测试selenium+接口>课程,5月25号开学! 主讲老师:上海-悠悠 上课方式:QQ群视频在线教学 本期上课时间:5月25号-7月28号,每周 ...
- 【JVM】垃圾收集器
程序计数器.Java虚拟机栈.本地方法栈分配的内存是确定的,生命周期与线程同样.所以不须要过多考虑回收问题. 而Java堆和方法区仅仅有运行时才知道有哪些对象被创建,须要多少内存,这部分的内存分配和回 ...
- Guava-Objects使用
前言 Java中的Object提供了很多方法供所有的类使用,特别是toString.hashCode.equals.getClass等方法,在日常开发中作用很大,Guava中包含Objects类,其提 ...
- 通过groovy表达式拓展oval——实现根据同一实体中的其他属性值对某个字段进行校验
在java的参数校验中,开源验证框架OVAL基本能够满足所有需求,如下面通过简单的添加注解,就可实现对参数的非空和长度校验. @NotNull(message="计息周期月数不能为空&quo ...
- iOS CALayer 绘图模糊有锯齿的解决方案
在CALayer中绘制图形会出现锯齿和模糊,同样绘图在UIView中就没有问题.经查资料发现不自动处理两倍像素的情况. 解决方案为:设置layer的contentsScale属性为[[UIScreen ...