# 一、粘包拆包問題的解決方案,有三種方案
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.發送信息或者接收信息的管道
小結:
客戶端通過服務器發送過來的數據進行拆包,通過編碼器進行編碼,然后放到管道中,接受到進行解碼