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协议是类似水流一样的数据传输方法.多次访问的时候可能出现粘包的问题,解决这种问题的方式有如下几种. 一.定长数据流 二.特殊结束符 三.
随机推荐
- 获取Gitlab项目的Token
获取Gitlab项目的Token 1.打开所需要Token的项目的主页进入CI/CD setting Setting -> CI/CD -> Genneral pioelines sett ...
- Python下载及Python最强大IDEPyCharm下载链接
Python下载: https://www.python.org/downloads/ PyCharm下载: https://www.jetbrains.com/pycharm/download/#s ...
- Java第一课
1.引入Java虚拟机原因?过程:源文件--编译器(使用javac命令)-----二进制的字节码文件(平台无关)--解释器(使用Java命令)-----可执行文件结论:Java中的跨平台是通过[JVM ...
- JS_高程5.引用类型(3)Array类型-检测数组
1. instanceof操作符(ECMAScript3) 对于一个网页,或者是一个全局作用域而言,使用instanceof操作符来检测数组就可以得到满意的结果. 语法:if(value instan ...
- ajax01
ajax01 1.ajax简介 涉及AJAX的操作页面不能用文件协议访问 使用ajax发送请求: send参数缺省默认为null onreadyatatechange事件在状态改变时就会触发. .re ...
- Linux之清理linux内存cache
转自:https://www.cnblogs.com/madsnotes/articles/5740495.html 频繁的文件访问会导致系统的Cache使用量大增.例如:在使用grep从很多文件中搜 ...
- too much recursion(太多递归)Uncaught RangeError: Maximum call stack size exceeded BootstrapValidator报错
在BootstrapValidator中已默认遵守Bootstrap规则,form里的每个输入项目必需包含在类为form-group的标签里,否则BootstrapValidator中定义的field ...
- hive使用python脚本导致java.io.IOException: Broken pipe异常退出
反垃圾rd那边有一个hql,在执行过程中出现错误退出,报java.io.IOException: Broken pipe异常,hql中使用到了python脚本,hql和python脚本最近没有人改过, ...
- html5使用canvas实现毫秒级画心电图
- MySQL 的 autocommit
在自动提交模式(autocommit=ON)下提交事务: •在自动提交模式下,每个SQL语句都是一个独立的事务. –mysql>insert into ACCOUNTS values(1,'To ...