# 一、粘包拆包问题的解决方案,有三种方案
1.消息固定长度,如果消息没有达到固定为大小,用空格补位
2.在包尾部添加特殊字符进行分割,回车
3消息=头+体,头包含消息的长度
如果想要了解什么是tcp粘包和拆包的问题 可以看这篇博客
我认为写的还可以:https://blog.csdn.net/hbtj_1216/article/details/53519894
# 二、DelimterBaseFrameDecoder(长度,容器里面的数据)
public class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
//FixedLengthFrameDecoder(5)
//表示固定长度发送消息 不足5位可以用空格补位
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture cf = b.connect("127.0.0.1", 8765).sync();
c**f.channel().writeAndFlush(Unpooled.wrappedBuffer("bbbb$_".getBytes()));
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("cccc$_".getBytes()));
**
//等待客户端端口关闭
cf.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
public class ClientHandler extends ChannelHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client channel active... ");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
String response = (String)msg;
System.out.println("Client: " + response);
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
服务端
public class Server {
public static void main(String[] args) throws Exception{
//1 创建2个线程,一个是负责接收客户端的连接。一个是负责进行数据传输的
EventLoopGroup pGroup = new NioEventLoopGroup();
EventLoopGroup cGroup = new NioEventLoopGroup();
//2 创建服务器辅助类
ServerBootstrap b = new ServerBootstrap();
b.group(pGroup, cGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_SNDBUF, 32*1024)
.option(ChannelOption.SO_RCVBUF, 32*1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//设置特殊分隔符
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
//设置字符串形式的解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
}
});
//4 绑定连接
ChannelFuture cf = b.bind(8765).sync();
//等待服务器监听端口关闭
cf.channel().closeFuture().sync();
pGroup.shutdownGracefully();
cGroup.shutdownGracefully();
}
}
public class ServerHandler extends ChannelHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(" server channel active... ");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String request = (String)msg;
System.out.println("Server :" + msg);
String response = "服务器响应:" + msg + "$_";
ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {
ctx.close();
}
}
# ## 总结:
服务器:为什么叫TCP粘包和,拆包,因为我们在通过http协议socket而Netty又是对socket底层协议的封装,主要是用于
通信协议上的问题
服务器怎么做的呢:
第一步:还是通过管道发布服务,
第二步:发送的内容进行解码
1.DelimiterBasedFrameDecoder(arg1,arg2)限制解码器的大小
2.StringDecoder:加上这个类去管道是说明采用什么样的解码器进行编码
第三步:注入接受和发送的处理器
3.发送信息或者接收信息的管道
客服端具体怎么做的呢
第一步:还是通过管道连接到服务器,
第二步:发送的内容进行解码
1.DelimiterBasedFrameDecoder(arg1,arg2)缓冲大小的大小和指定分隔符
2.StringDecoder:加上这个类去管道是说明采用什么样的解码器进行编码
3.发送信息或者接收信息的管道
第三步:注入接受和发送的处理器
3.发送信息或者接收信息的管道
小结:
客户端通过服务器发送过来的数据进行拆包,通过编码器进行编码,然后放到管道中,接受到进行解码