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的基础上封装的便于用户开发网络应用程 ...
随机推荐
- Linux-IIC驱动(详解)
IIC接口下的24C02 驱动分析: http://www.cnblogs.com/lifexy/p/7793686.html 接下来本节, 学习Linux下如何利用linux下I2C驱动体系结构来操 ...
- Ubuntu 命令行连接WiFi
查看是否已经正确安装无线网卡 iwconfig .启动无线网卡, 如果网卡是wlan0 # 方式1 ifconfig wlan0 up # 或者方式2 ip link set wlan0 up .扫描 ...
- 搭建Nuxt项目(搭配Element UI、axios)
使用Nuxt Nuxt.js文档:https://zh.nuxtjs.org/guide/ 开始 初始化Nuxt项目 npx create-nuxt-app <项目名> // or yar ...
- 在input内添加小图标或文字(元/月)等
文字: <td class="formValue"> <div class="input-group"> <input id=&q ...
- Python之Pandas绘图,设置显示中文问题
# -*- coding: utf-8 -*- # author:baoshan import pandas as pd import matplotlib.pyplot as plt plt.rcP ...
- python中的修饰符@的作用
1.一层修饰符 1)简单版,编译即实现 在一个函数上面添加修饰符 @另一个函数名 的作用是将这个修饰符下面的函数作为该修饰符函数的参数传入,作用可以有比如你想要在函数前面添加记录时间的代码,这样每个函 ...
- Spring4.X整合redis
包和版本的依赖关系很严重 我的配置 spring-data-redis-1.6.6.RELEASE.jar spring-tx-4.2.5.RELEASE.jar redis-2.7.2.jar co ...
- VueX(vue状态管理)简单小实例
VueX:状态管理 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 核心模块:State. ...
- AMSR-E/AMSR-2数据介绍与下载
1 AMSR-E数据介绍 The Advanced Microwave Scanning Radiometer for EOS (AMSR-E)是ADEOS-II 上的AMSR的改进版本, 是JAXA ...
- 使用Matlab绘制三维图的几种方法
以下六个函数都可以实现绘制三维图像: surf(xx,yy,zz); surfc(xx,yy,zz); mesh(xx,yy,zz); meshc(xx,yy,zz); meshz(xx,yy,zz) ...