netty(一) 利用 LineBasedFrameDecoder,StringDecoder解决TCP粘包/拆包问题
【摘要】 .一,TCP粘包/拆包问题图示
产生TCP粘包/拆包问题如下几点:
TCP粘包/拆包问题解决方案:
二,利用 LineBasedFrameDecoder,StringDecoder解决TCP粘包/拆包问题
server端代码示例:
package nettyDemo3; import io.netty.bootstrap.ServerBoot...
.一,TCP粘包/拆包问题图示
产生TCP粘包/拆包问题如下几点:
TCP粘包/拆包问题解决方案:
二,利用 LineBasedFrameDecoder,StringDecoder解决TCP粘包/拆包问题
server端代码示例:
package nettyDemo3;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
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;
public class TimeServerHanler extends ChannelHandlerAdapter {
private int counter; // 计数器
/**
* 抛异常会调用此方法
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
// super.exceptionCaught(ctx, cause);
cause.printStackTrace();
ctx.close();
}
/**
* 读取客户端回应的消息
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
// super.channelRead(ctx, msg);
// ByteBuf buf = (ByteBuf) msg;
// byte[] bytes = new byte[buf.readableBytes()];
// buf.readBytes(bytes);
// String body = new String(bytes, "UTF-8");
// System.getProperty("line.separator") 换行符
String body = (String) msg;
System.out.println(body + "【第" + (++counter) + "次收到客户端的消息】");
String result = "i am server" + System.getProperty("line.separator");
ByteBuf buf2 = Unpooled.copiedBuffer(result.getBytes());
ctx.write(buf2);
}
/**
* 读取完成之后会调用此方法
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
// super.channelReadComplete(ctx);
ctx.flush();
System.out.println("读取完成");
}
public static void main(String[] args) {
// 配置服务端线程组,一个负责连接 ,一个负责读写
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
// 创建服务端辅助启动类并设置参数
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
// 添加回车换行符解码器
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new TimeServerHanler());
}
});
int inetPort = 8080;
// 绑定端口,并开始阻塞等待客户端的连接
ChannelFuture f = bootstrap.bind(inetPort).sync();
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 优雅退出,释放线程池资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
client端代码示例:
package nettyDemo3;
import org.omg.PortableServer.POA;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
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 TimeClientHandler extends ChannelHandlerAdapter {
private int counter;
/**
* 抛异常会调用此方法
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
// super.exceptionCaught(ctx, cause);
ctx.close();
cause.printStackTrace();
}
/**
* 当客户端成功连接上服务端之后会调用此方法
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
// super.channelActive(ctx);
byte[] msg = ("i am clien" + System.getProperty("line.separator")).getBytes();
ByteBuf buf = null;
for (int i = 0; i < 50; i++) {
buf = Unpooled.buffer(msg.length);
buf.writeBytes(msg);
ctx.writeAndFlush(buf);
}
}
/**
* 读取服务端回应的消息
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
// super.channelRead(ctx, msg);
// ByteBuf buf = (ByteBuf) msg;
// byte[] bytes = new byte[buf.readableBytes()];
// buf.readBytes(bytes);
// String body = new String(bytes, "UTF-8");
String body = (String) msg;
System.out.println(body + "【第" + (++counter) + "次收到服务端的消息】");
}
public static void main(String[] args) {
// 配置客户端端线程组负责读写
EventLoopGroup work = new NioEventLoopGroup();
try {
// 创建客户端的辅助启动类并设置参数
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(work).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
// 添加解码器
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new TimeClientHandler());
}
});
final String host = "127.0.0.1";
final int port = 8080;
// 连接服务端
ChannelFuture future = bootstrap.connect(host, port).sync();
future.channel().closeFuture().sync();
} catch (Exception e) {
// TODO: handle exception
} finally {
// 优雅退出,释放线程池资源
work.shutdownGracefully();
}
}
}
分别运行客户端和服务端实例,看到控制台输出以下图片中的内容,说明成功解决tcp粘包/拆包问题。
附: netty利用DelimiterBasedFrameDecoder 和 FixedLengthFrameDecoder 也可以按需自定义解码实现粘包/拆包问题
//添加自定义以$_为分隔符的解码器
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
//添加固定长度解码器
ch.pipeline().addLast(new FixedLengthFrameDecoder(13));
文章来源: blog.csdn.net,作者:血煞风雨城2018,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_31905135/article/details/81736896
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)