一起学Netty(六)之 TCP粘包拆包场景

TCP编程底层都有粘包和拆包机制,因为我们在C/S这种传输模型下,以TCP协议传输的时候,在网络中的byte其实就像是河水,TCP就像一个搬运工,将这流水从一端转送到另一端,这时又分两种情况:

1)如果客户端的每次制造的水比较多,也就是我们常说的客户端给的包比较大,TCP这个搬运工就会分多次去搬运。

2)如果客户端每次制造的水比较少的话,TCP可能会等客户端多次生产之后,把所有的水一起再运输到另一端


上述第一种情况,就是需要我们进行粘包,在另一端接收的时候,需要把多次获取的结果粘在一起,变成我们可以理解的信息,第二种情况,我们在另一端接收的时候,就必须进行拆包处理,因为每次接收的信息,可能是另一个远程端多次发送的包,被TCP粘在一起的


我们进行上述两种情况给出具体的场景:

1)单次发送的包内容过多的情况,拆包的现象:

我们先写客户端的bootstrap:

[java]  view plain  copy
  1. package com.lyncc.netty.stickpackage.myself;  
  2.   
  3. import io.netty.bootstrap.Bootstrap;  
  4. import io.netty.channel.ChannelFuture;  
  5. import io.netty.channel.ChannelInitializer;  
  6. import io.netty.channel.ChannelOption;  
  7. import io.netty.channel.ChannelPipeline;  
  8. import io.netty.channel.EventLoopGroup;  
  9. import io.netty.channel.nio.NioEventLoopGroup;  
  10. import io.netty.channel.socket.SocketChannel;  
  11. import io.netty.channel.socket.nio.NioSocketChannel;  
  12. import io.netty.handler.codec.LineBasedFrameDecoder;  
  13. import io.netty.handler.codec.string.StringDecoder;  
  14.   
  15. public class BaseClient {  
  16.       
  17.     static final String HOST = System.getProperty("host""127.0.0.1");  
  18.     static final int PORT = Integer.parseInt(System.getProperty("port""8080"));  
  19.     static final int SIZE = Integer.parseInt(System.getProperty("size""256"));  
  20.   
  21.     public static void main(String[] args) throws Exception {  
  22.   
  23.         EventLoopGroup group = new NioEventLoopGroup();  
  24.         try {  
  25.             Bootstrap b = new Bootstrap();  
  26.             b.group(group)  
  27.              .channel(NioSocketChannel.class)  
  28.              .option(ChannelOption.TCP_NODELAY,true)  
  29.              .handler(new ChannelInitializer<SocketChannel>() {  
  30.                  @Override  
  31.                  public void initChannel(SocketChannel ch) throws Exception {  
  32.                      ChannelPipeline p = ch.pipeline();  
  33. //                     p.addLast(new LineBasedFrameDecoder(1024));  
  34.                      p.addLast(new StringDecoder());  
  35.                      p.addLast(new BaseClientHandler());  
  36.                  }  
  37.              });  
  38.   
  39.             ChannelFuture future = b.connect(HOST, PORT).sync();  
  40.             future.channel().writeAndFlush("Hello Netty Server ,I am a common client");  
  41.             future.channel().closeFuture().sync();  
  42.         } finally {  
  43.             group.shutdownGracefully();  
  44.         }  
  45.     }  
  46.   
  47. }  
客户端的handler:

[java]  view plain  copy
  1. package com.lyncc.netty.stickpackage.myself;  
  2.   
  3. import io.netty.buffer.ByteBuf;  
  4. import io.netty.buffer.Unpooled;  
  5. import io.netty.channel.ChannelHandlerContext;  
  6. import io.netty.channel.ChannelInboundHandlerAdapter;  
  7.   
  8. public class BaseClientHandler extends ChannelInboundHandlerAdapter{  
  9.       
  10.     private byte[] req;  
  11.       
  12.     private int counter;  
  13.       
  14.     public BaseClientHandler() {  
  15. //        req = ("BazingaLyncc is learner" + System.getProperty("line.separator"))  
  16. //            .getBytes();  
  17.         req = ("In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. His book w"  
  18.                 + "ill give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the process "  
  19.                 + "of configuring and connecting all of Netty’s components to bring your learned about threading models in ge"  
  20.                 + "neral and Netty’s threading model in particular, whose performance and consistency advantages we discuss"  
  21.                 + "ed in detail In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. Hi"  
  22.                 + "s book will give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the"  
  23.                 + " process of configuring and connecting all of Netty’s components to bring your learned about threading "  
  24.                 + "models in general and Netty’s threading model in particular, whose performance and consistency advantag"  
  25.                 + "es we discussed in detailIn this chapter you general, we recommend Java Concurrency in Practice by Bri"  
  26.                 + "an Goetz. His book will give We’ve reached an exciting point—in the next chapter;the counter is: 1 2222"  
  27.                 + "sdsa ddasd asdsadas dsadasdas").getBytes();  
  28.     }  
  29.       
  30.     @Override  
  31.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  32.         ByteBuf message = null;  
  33. //        for (int i = 0; i < 100; i++) {  
  34. //            message = Unpooled.buffer(req.length);  
  35. //            message.writeBytes(req);  
  36. //            ctx.writeAndFlush(message);  
  37. //        }  
  38.         message = Unpooled.buffer(req.length);  
  39.         message.writeBytes(req);  
  40.         ctx.writeAndFlush(message);  
  41.         message = Unpooled.buffer(req.length);  
  42.         message.writeBytes(req);  
  43.         ctx.writeAndFlush(message);  
  44.     }  
  45.       
  46.     @Override  
  47.     public void channelRead(ChannelHandlerContext ctx, Object msg)  
  48.         throws Exception {  
  49.         String buf = (String) msg;  
  50.         System.out.println("Now is : " + buf + " ; the counter is : "+ ++counter);  
  51.     }  
  52.   
  53.     @Override  
  54.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
  55.         ctx.close();  
  56.     }  
  57.       
  58.       
  59.   
  60. }  
服务端的serverBootstrap:

[java]  view plain  copy
  1. package com.lyncc.netty.stickpackage.myself;  
  2.   
  3. import io.netty.bootstrap.ServerBootstrap;  
  4. import io.netty.channel.ChannelFuture;  
  5. import io.netty.channel.ChannelInitializer;  
  6. import io.netty.channel.ChannelOption;  
  7. import io.netty.channel.EventLoopGroup;  
  8. import io.netty.channel.nio.NioEventLoopGroup;  
  9. import io.netty.channel.socket.SocketChannel;  
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  11. import io.netty.handler.codec.string.StringDecoder;  
  12.   
  13. import java.net.InetSocketAddress;  
  14.   
  15. public class BaseServer {  
  16.   
  17.     private int port;  
  18.       
  19.     public BaseServer(int port) {  
  20.         this.port = port;  
  21.     }  
  22.       
  23.     public void start(){  
  24.         EventLoopGroup bossGroup = new NioEventLoopGroup(1);  
  25.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
  26.         try {  
  27.             ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))  
  28.                     .childHandler(new ChannelInitializer<SocketChannel>() {  
  29.                           
  30.                         protected void initChannel(SocketChannel ch) throws Exception {  
  31. //                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024));  
  32.                             ch.pipeline().addLast(new StringDecoder());  
  33.                             ch.pipeline().addLast(new BaseServerHandler());  
  34.                         };  
  35.                           
  36.                     }).option(ChannelOption.SO_BACKLOG, 128)     
  37.                     .childOption(ChannelOption.SO_KEEPALIVE, true);  
  38.              // 绑定端口,开始接收进来的连接  
  39.              ChannelFuture future = sbs.bind(port).sync();    
  40.                
  41.              System.out.println("Server start listen at " + port );  
  42.              future.channel().closeFuture().sync();  
  43.         } catch (Exception e) {  
  44.             bossGroup.shutdownGracefully();  
  45.             workerGroup.shutdownGracefully();  
  46.         }  
  47.     }  
  48.       
  49.     public static void main(String[] args) throws Exception {  
  50.         int port;  
  51.         if (args.length > 0) {  
  52.             port = Integer.parseInt(args[0]);  
  53.         } else {  
  54.             port = 8080;  
  55.         }  
  56.         new BaseServer(port).start();  
  57.     }  
  58. }  
服务端的handler:

[java]  view plain  copy
  1. package com.lyncc.netty.stickpackage.myself;  
  2.   
  3. import io.netty.channel.ChannelHandlerContext;  
  4. import io.netty.channel.ChannelInboundHandlerAdapter;  
  5.   
  6. public class BaseServerHandler extends ChannelInboundHandlerAdapter{  
  7.       
  8.       
  9.     private int counter;  
  10.       
  11.       
  12.     @Override  
  13.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
  14.           
  15.         String body = (String)msg;  
  16.         System.out.println("server receive order : " + body + ";the counter is: " + ++counter);  
  17.     }  
  18.       
  19.       
  20.     @Override  
  21.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
  22.         cause.printStackTrace();  
  23.         ctx.close();  
  24.     }  
  25.   
  26. }  

照例,我们先运行服务器端:

我们再运行客户端,客户端启动后,我们再看看服务器端的控制台打印输出:

我们可以看到服务器端分三次接收到了客户端两次发送的那段很长的信息


2)单次发送的包内容过多的情况,粘包的现象:

客户端和服务端的bootstrap不改变,我们修改一下,客户端发送信息的channelActive的代码:

[java]  view plain  copy
  1. package com.lyncc.netty.stickpackage.myself;  
  2.   
  3. import io.netty.buffer.ByteBuf;  
  4. import io.netty.buffer.Unpooled;  
  5. import io.netty.channel.ChannelHandlerContext;  
  6. import io.netty.channel.ChannelInboundHandlerAdapter;  
  7.   
  8. public class BaseClientHandler extends ChannelInboundHandlerAdapter{  
  9.       
  10.     private byte[] req;  
  11.       
  12.     private int counter;  
  13.       
  14.     public BaseClientHandler() {  
  15.         req = ("BazingaLyncc is learner").getBytes();  
  16. //        req = ("In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. His book w"  
  17. //                + "ill give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the process "  
  18. //                + "of configuring and connecting all of Netty’s components to bring your learned about threading models in ge"  
  19. //                + "neral and Netty’s threading model in particular, whose performance and consistency advantages we discuss"  
  20. //                + "ed in detail In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. Hi"  
  21. //                + "s book will give We’ve reached an exciting point—in the next chapter we’ll discuss bootstrapping, the"  
  22. //                + " process of configuring and connecting all of Netty’s components to bring your learned about threading "  
  23. //                + "models in general and Netty’s threading model in particular, whose performance and consistency advantag"  
  24. //                + "es we discussed in detailIn this chapter you general, we recommend Java Concurrency in Practice by Bri"  
  25. //                + "an Goetz. His book will give We’ve reached an exciting point—in the next chapter;the counter is: 1 2222"  
  26. //                + "sdsa ddasd asdsadas dsadasdas").getBytes();  
  27.     }  
  28.       
  29.     @Override  
  30.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  31.         ByteBuf message = null;  
  32.         for (int i = 0; i < 100; i++) {  
  33.             message = Unpooled.buffer(req.length);  
  34.             message.writeBytes(req);  
  35.             ctx.writeAndFlush(message);  
  36.         }  
  37. //        message = Unpooled.buffer(req.length);  
  38. //        message.writeBytes(req);  
  39. //        ctx.writeAndFlush(message);  
  40. //        message = Unpooled.buffer(req.length);  
  41. //        message.writeBytes(req);  
  42. //        ctx.writeAndFlush(message);  
  43.     }  
  44.   
  45.     @Override  
  46.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
  47.         ctx.close();  
  48.     }  
  49.   
  50. }  
我们再次启动服务器端:


启动客户端后,依旧看服务器端的控制台:

可以看出,客户端发送100次的信息,被服务器端分三次就接收了,这就发生了粘包的现象


以上就是典型的粘包和拆包的场景

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值