TCP--粘包拆包,netty的解决方式
TCP基于链接的协议,并且保证有序性。
但是,每个包的长度,需要明确,否则会发生粘包现象。
以下示例为一个自定义协议的例子,其中包含了拆包的内容。
所有的类:
协议类:
public class PersonProtocol {
private int length;
private byte[] content;
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
}
解码器类:
public class PersonProtocolDecode extends ReplayingDecoder<Void> {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
System.out.println("decode invoke!");
//拆包的内容如下:先获取长度,再根据获取的长度,获取到包内的内容。
int length = in.readInt();
byte[] content = new byte[length];
//获取到内容
in.readBytes(content);
PersonProtocol personProtocol = new PersonProtocol();
personProtocol.setLength(length);
personProtocol.setContent(content);
out.add(personProtocol);
}
}
编码器类:
public class PersonProtocolEncode extends MessageToByteEncoder<PersonProtocol>{
@Override
protected void encode(ChannelHandlerContext ctx, PersonProtocol msg, ByteBuf out) throws Exception {
System.out.println("encode invoke!");
out.writeInt(msg.getLength());
out.writeBytes(msg.getContent());
//不需要flush的原因是,此时还是在jvm内部处理代码,并未涉及到io
}
}
服务器处理类:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset;
import java.util.UUID; public class ServerHandler extends SimpleChannelInboundHandler<PersonProtocol>{
private int count = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, PersonProtocol msg) throws Exception {
System.out.println("接收到的消息长度:"+msg.getLength()
+",消息内容: "+new String(msg.getContent(), Charset.forName("utf-8")));
System.out.println("消息的次数:"+ ++count);
PersonProtocol result = new PersonProtocol();
UUID uuid = UUID.randomUUID();
byte[] count = uuid.toString().getBytes(Charset.forName("utf-8"));
System.out.println("发给客户端的数据为:长度"+count.length+",内容:"+uuid );
result.setLength(count.length);
result.setContent(count);
ctx.channel().writeAndFlush(result);
}
}
客户端处理类:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset; public class ClientHandler extends SimpleChannelInboundHandler<PersonProtocol>{
private int count = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, PersonProtocol msg) throws Exception {
System.out.println("接收到的消息长度"+msg.getLength()
+",消息内容: "+new String(msg.getContent(), Charset.forName("utf-8")));
System.out.println("消息的次数:"+ ++count);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
String str = "你好吗?,我很好!,你好吗?我很好!";
for(int i = 0;i < str.split(",").length;i++){
String temp = str.split(",")[i];
System.out.println(temp+",i:"+i);
PersonProtocol pp = new PersonProtocol();
pp.setLength(temp.getBytes(Charset.forName("utf-8")).length);
pp.setContent(temp.getBytes(Charset.forName("utf-8")));
ctx.writeAndFlush(pp);
}
}
}
服务端启动类:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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 NettyServer {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup(1); //分发事件循环组
EventLoopGroup workGroup = new NioEventLoopGroup();//处理通道事件循环组
ServerBootstrap serverBootstrap = new ServerBootstrap();//初始化服务器
serverBootstrap.group(bossGroup,workGroup) //将两个循环组绑定到服务器
.channel(NioServerSocketChannel.class) //指定通道类型,当前使用NIO模式
.childHandler(new ChannelInitializer<SocketChannel>(){ //指定通道中的过滤器链
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new PersonProtocolDecode()); //解码器过滤
pipeline.addLast(new PersonProtocolEncode());//编码器
pipeline.addLast(new ServerHandler());//具体的业务处理,一般放在最后面
}
});
ChannelFuture channelFuture = serverBootstrap.bind(12345).sync();//绑定到本机的12345端口,等待同步处理结果
channelFuture.channel().closeFuture().sync();//阻塞等待closeFuture的返回,同步等待
bossGroup.shutdownGracefully();//优雅关闭
workGroup.shutdownGracefully();
}
}
客户端启动类:
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; public class NettyClient {
public static void main(String[] args) throws Exception{
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).
handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new PersonProtocolDecode());
pipeline.addLast(new PersonProtocolEncode());
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("localhost", 12345).sync();
channelFuture.channel().closeFuture().sync();//客户端阻塞,一直运行。
eventLoopGroup.shutdownGracefully();//优雅关闭
}
}
运行服务端,再运行客户端,即可完成测试。
TCP--粘包拆包,netty的解决方式的更多相关文章
- TCP粘包/拆包问题的解决
TCP粘包拆包问题 一个完整的包可能被TCP拆分成多个包,或多个小包封装成一个大的数据包发送. 解决策略 消息定长,如果不够,空位补空格 在包尾增加回车换行符进行分割,例如FTP协议 将消息分为消息头 ...
- 第四章 TCP粘包/拆包问题的解决之道---4.1---
4.1 TCP粘包/拆包 TCP是一个“流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可 ...
- 第四章 TCP粘包/拆包问题的解决之道---4.2--- 未考虑TCP粘包导致功能异常案例
4.2 未考虑TCP粘包导致功能异常案例 如果代码没有考虑粘包/拆包问题,往往会出现解码错位或者错误,导致程序不能正常工作. 4.2.1 TimeServer 的改造 Class : TimeServ ...
- Netty使用LineBasedFrameDecoder解决TCP粘包/拆包
TCP粘包/拆包 TCP是个”流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TC ...
- 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)
一.粘包/拆包概念 TCP是一个“流”协议,所谓流,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的划分,所以在业务上认 ...
- 深入学习Netty(5)——Netty是如何解决TCP粘包/拆包问题的?
前言 学习Netty避免不了要去了解TCP粘包/拆包问题,熟悉各个编解码器是如何解决TCP粘包/拆包问题的,同时需要知道TCP粘包/拆包问题是怎么产生的. 在此博文前,可以先学习了解前几篇博文: 深入 ...
- Netty(三)TCP粘包拆包处理
tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. 粘包.拆包问题说明 假设客户端分别发送数据包D1和D ...
- Netty(二)——TCP粘包/拆包
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7814644.html 前面讲到:Netty(一)--Netty入门程序 主要内容: TCP粘包/拆包的基础知 ...
- TCP粘包/拆包(Netty权威指南)
无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个“流”协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片 ...
- TCP粘包/拆包 ByteBuf和channel 如果没有Netty? 传统的多线程服务器,这个也是Apache处理请求的模式
通俗地讲,Netty 能做什么? - 知乎 https://www.zhihu.com/question/24322387 谢邀.netty是一套在java NIO的基础上封装的便于用户开发网络应用程 ...
随机推荐
- element-ui表格显示html格式
<el-table-column type="String" label="内容" prop="tpl" width="58 ...
- currency
currency 美 ['kʌrənsi] 英 ['kʌrənsi] n.货币:通货:通用:流行 网络流通:货币型:币种
- deepin常用软件列表
deepin常用软件列表 软件列表 Safe Eyes 视力保护程序 网址
- (转)设置了RemoveIPC=yes 的RHEL7.2 会crash掉Oracle asm 实例和Oracle database实例
设置了RemoveIPC=yes 的RHEL7.2 会crash掉Oracle asm 实例和Oracle database实例,该问题也会在使用Shared Memory Segment (SHM ...
- Andorid SQLite数据库开发基础教程(2)
Andorid SQLite数据库开发基础教程(2) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库.
- 内存检测工具valgrind的安装和简单使用
1. 安装 .tar.bz2 cd valgrind- sudo ./configure sudo make sudo make install 2. 简单使用 #include <stdio. ...
- 让pc端代码适用移动端——<meta name="viewport"
写的代码,在pc端运行正常,在移动端就很小很小,需要放大.这时候可引入这个标签 @参考博客 用法,在<head></head>中添加<meta name="vi ...
- 如何让winrar5压缩的文件能用低版本winrar打开
https://jingyan.baidu.com/article/39810a2348ab24b636fda681.html 在压缩文件格式选项处点选[RAR4]选项,即之前版本的winrar支持的 ...
- 【k8s secret token 删掉自动重建】kubernetes secret 和 serviceaccount
https://stackoverflow.com/questions/54354243/kubernetes-secret-is-persisting-through-deletes
- elasticsearch5.0.1集群索引分片丢失的处理
elasticdump命令安装 yum install npm npm install elasticdump -g 命令安装完毕,可以测试. 可能会报出nodejs的版本之类的错误,你需要升级一下版 ...