netty 解决粘包拆包问题
netty server
TimeServer
package com.zhaowb.netty.ch4_3; 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;
import io.netty.handler.codec.string.StringEncoder; public class TimeServer { public void bind(int port) throws Exception { // 配置 服务端的 NIO 线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChildChannelHandler()); // 绑定端口,同步等待成功。
ChannelFuture f = b.bind(port).sync();
// 等待服务端监听端口关闭。
f.channel().closeFuture().sync();
} catch (Exception e) {
// 退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} private class ChildChannelHandler extends 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 TimeServerHandler());
}
} public static void main(String[] args) throws Exception {
int port = 8080; if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
new TimeServer().bind(port);
}
}
TimeServerHandler
package com.zhaowb.netty.ch4_3; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import java.util.Date; public class TimeServerHandler extends ChannelHandlerAdapter { private int counter; @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String body = (String) msg; System.out.println("The time server receive order : " + body + " ; the counter is : " + ++counter);
String currentTime = "QUERY TIME ORDER"
.equalsIgnoreCase(body) ? new Date(
System.currentTimeMillis()).toString()
: "BAD ORDER";
currentTime = currentTime + System.getProperty("line.separator");
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.writeAndFlush(resp);
} /**
* 当监听到端口时调用 channelActive 打印 "连接成功!"
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接成功!");
} /**
* 当出现异常时,关闭连接
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("出现异常,关闭");
ctx.close();
}
}
netty client
TimeClient
package com.zhaowb.netty.ch4_3; 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; public class TimeClient { public void connect(int port, String host) throws Exception { //配置客户端 NIO 线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.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 f = b.connect(host, port).sync();
// 等待客户端链路关闭
f.channel().closeFuture().sync();
} finally {
// 释放 NIO 线程组
group.shutdownGracefully(); }
} public static void main(String[] args) throws Exception {
int port = 8080; if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
new TimeClient().connect(port, "127.0.0.1");
}
}
TimeClientHandler
package com.zhaowb.netty.ch4_3; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import java.util.logging.Logger; public class TimeClientHandler extends ChannelHandlerAdapter { private static final Logger logger = Logger.getLogger(TimeClientHandler.class.getName()); private int counter; private byte[] req; public TimeClientHandler() {
req = ("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();
} /**
* 当连接成功时,调用 writeAndFlush 发送 firstMessage 到服务端
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ByteBuf message = null;
for (int i = 0; i < 100; i++){
message = Unpooled.buffer(req.length);
message.writeBytes(req);
ctx.writeAndFlush(message);
}
} /**
* 当服务端的有数据发送过来时,调用 channelRead 接受数据,并打印
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String body = (String) msg;
System.out.println("Now is : " + body + " ; the counter is : " + ++counter);
} /**
* 出现异常时,打印错误,并关闭
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.warning("Unexpected Exception from downstream : " + cause.getMessage());
ctx.close();
}
}
解决粘包拆包问题的关键是使用了
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new StringDecoder());
这个程序的运行还是有一些理想的情况,在发送的数据结尾添加System.getProperty("line.separator"),如果没有,将会无法解析
LineBasedFrameDecoder: 的工作原理是它一次遍历 ByteBuf 中的刻度字节,判断看是否有 “\n” 或者 "\r\n",
如果有就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行,它是以换行符为结束标志 的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度。如果连续读取到最大长度后仍没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流。
StringDecoder: 的功能非常简单,就是将接收到的对象转换成字符串,然后继续调用后面的 handle。
LineBasedFrameDecoder + StringDecoder 组合就是换行切换的文本编辑器,被设计出来用来支持 TCP 的粘包和拆包。
netty 解决粘包拆包问题的更多相关文章
- netty: 解决粘包拆包: 分隔符DelimiterBasedFrameDecoder,定长消息FixedLengthFrameDecoder
DelimiterBasedFrameDecoder 自定义分隔符 给Server发送多条信息,但是server会讲多条信息合并为一条.这时候我们需要对发生的消息指定分割,让client和server ...
- Netty入门系列(2) --使用Netty解决粘包和拆包问题
前言 上一篇我们介绍了如果使用Netty来开发一个简单的服务端和客户端,接下来我们来讨论如何使用解码器来解决TCP的粘包和拆包问题 TCP为什么会粘包/拆包 我们知道,TCP是以一种流的方式来进行网络 ...
- Netty TCP粘包/拆包问题《二》
1.DelimiterBasedFrameDecoder:是以分隔符作为结束标志进行解决粘包/拆包问题 代码: EchoClient:客户端 /* * Copyright 2012 The Netty ...
- netty解决粘包半包问题
前言:开发者用到TCP/IP交互时,偶尔会遇到粘包或者半包的数据,这种情况有时会对我们的程序造成严重的影响,netty框架为解决这种问题提供了若干框架 1. LineBasedFrameDecoder ...
- Netty解决粘包和拆包问题的四种方案
在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接.由于微服务往对方发送信息的时候,所有的请求都是使 ...
- 《精通并发与Netty》学习笔记(14 - 解决TCP粘包拆包(二)Netty自定义协议解决粘包拆包)
一.Netty粘包和拆包解决方案 Netty提供了多个解码器,可以进行分包的操作,分别是: * LineBasedFrameDecoder (换行) LineBasedFrameDecoder是回 ...
- Netty TCP粘包/拆包问题《一》
1.使用LineBasedFrameDecoder,StringDecoder解析器进行解决TCP粘包/拆包问题 2.代码搞起: TimeClient:客户端 /* * Copyright 2013- ...
- 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)
一.粘包/拆包概念 TCP是一个“流”协议,所谓流,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的划分,所以在业务上认 ...
- Netty 粘包 & 拆包 & 编码 & 解码 & 序列化 介绍
目录: 粘包 & 拆包及解决方案 ByteToMessageDecoder 基于长度编解码器 基于分割符的编解码器 google 的 Protobuf 序列化介绍 其他的 前言 Netty 作 ...
随机推荐
- bzoj1096题解
[解题思路] 预处理spi=∑pj(j∈[1,i]),si=si-1+(xi-xi-1)*spi-1表示把工厂1~i-1的产品都运到工厂i的花费.于是把工厂j+1~i的产品都运到工厂i的花费为si-s ...
- bzoj1013题解
[解题思路] 初看以为是二次方程组,但这些方程有相同的右值r2,于是可以化为一次方程组,高斯消元即可.复杂度O(n3). 化简过程: 假设第i个方程和第j个方程联立,得: ∑(a[i,k]-a[0, ...
- 概率期望+闭包+bitset优化——hdu5036
我们首先得到: 暴力打开这个箱子,能够开那些箱子.这个可以用bitset来进行状态压缩. 用闭包传递来解决这一步 然后,对于每个箱子,我们考虑有多少种方法,使:暴力打开某些箱子,同时能 ...
- Flume详解
Flume是一种分布式,可靠且可用的服务,用于有效地收集,聚合和移动大量日志数据.它具有基于流数据流的简单灵活的架构.它具有可靠的可靠性机制和许多故障转移和恢复机制,具有强大的容错性.它使用简单的可扩 ...
- PyTorch常用函数总结
将一个tensor分到多个GPU上:torch.cuda.comm.scatter
- LeetCode 181. Employees Earning More Than Their Managers (超过经理收入的员工)
题目标签: 题目给了我们一个 员工表,包括经理.员工会有经理的id. 这里可以重复 利用两次 表格,表格a, 表格b,当a 员工的经理id 等于 b员工时候,在从中找到员工工资大于经理的.具体看co ...
- hive简述
显示表头,当前终端有效 set hive.cli.print.header=true; 查看表结构 desc table; 详细的表结构 desc formatted table; 删除表 drop ...
- Instrumentation 实践详解
原文地址:https://blog.csdn.net/pengjunlee/article/details/72717622
- icmp隧道--icmpsh
本地:ubantu 目标主机:windows 在ubantu上关闭自带的icmp回应 sysctl -w net.ipv4.icmp_echo_ighore_all=1 ubantu上启动 pip i ...
- 2.2_springboot2.x消息RabbitMQ整合&amqpAdmin管理组件的使用
5.1.1.基本测试 1.引 spring-boot-starter-amqp** <dependencies> <dependency> <groupId>org ...