2.Netty的粘包、拆包(一)

Netty粘包、拆包

1.什么是拆包、粘包

(1)拆包、粘包介绍

TCP是个“流”协议,所谓流,就是没有界限的一串数据。大家可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

(2)图解

(3)代码模拟

  1. 服务端Server

    package com.xm.netty.demo02;
    
    import java.net.InetSocketAddress;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    public class Server {
    	
    	private final int port;
    
    	public Server(int port) {
    		this.port = port;
    	}
    
    
    
    	public static void main(String[] args) {
    		
    		int port = 8989;
    		try {
    			new Server(port).start();
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    
    	}
    
    
    
    	private void start() throws InterruptedException {
    		EventLoopGroup g1 = new NioEventLoopGroup();
    		EventLoopGroup g2 = new NioEventLoopGroup();
    		try {
    			ServerBootstrap bootstrap = new ServerBootstrap();
    			 bootstrap
    			 		.group(g1,g2)
    			 		.channel(NioServerSocketChannel.class)
    			 		.localAddress(new InetSocketAddress( port))
    			 		.childHandler(new ChannelInitializer() {
    			 			@Override
    			 			protected void initChannel(Channel ch) throws Exception {
    			 				ch.pipeline().addLast(new ServerHandler());
    			 			}
    					});
    			 ChannelFuture future = bootstrap.bind().sync();
    			 future.channel().closeFuture().sync();
    		} finally {
    			g1.shutdownGracefully().sync();
    			g2.shutdownGracefully().sync();
    		}
    	}
    
    }
    
    
  2. 服务端ServerHandler

    package com.xm.netty.demo02;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.util.CharsetUtil;
    
    public class ServerHandler extends ChannelHandlerAdapter {
    	
    	@Override
    	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    		
    		ByteBuf in = (ByteBuf) msg;
    		String str = in.toString(CharsetUtil.UTF_8);
    		System.out.println("Server:"+str);
    		str = "服务器返回--->"+ str;
    		ctx.writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
    	}
    	
    	@Override
    	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    		cause.printStackTrace();
    		ctx.close();
    	}
    	
    	@Override
    	public void channelActive(ChannelHandlerContext ctx) throws Exception {
    		System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())+"一个客户端连接!");
    	}
    	
    
    }
    
    
  3. 客户端Client

    package com.xm.netty.demo02;
    
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    public class Client {
    	
    	private final int port;
    	private final String host;
    	
    	
    
    	public Client(int port, String host) {
    		this.port = port;
    		this.host = host;
    	}
    
    	public static void main(String[] args) {
    		String host = "127.0.0.1";
    		int port = 8989;
    		try {
    			new Client(port, host).start();
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    	private void start() throws InterruptedException {
    		
    		EventLoopGroup group = new NioEventLoopGroup();
    		try {
    			Bootstrap bootstrap = new Bootstrap();
    			bootstrap
    					.group(group)
    					.channel(NioSocketChannel.class)
    					.remoteAddress(host, port)
    					.handler(new ChannelInitializer<SocketChannel>() {
    
    						@Override
    						protected void initChannel(SocketChannel ch) throws Exception {
    							ch.pipeline().addLast(new ClientHandler());
    						}
    						
    					});
    			
    			ChannelFuture future = bootstrap.connect().sync();
    			
    			for(int i=10;i<20;i++) {
    				String str = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()) + "---- " +i+"<<<";
    				future.channel().writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
    			}
    			
    			
    			
    			
    			future.channel().closeFuture().sync();
    		} finally {
    			group.shutdownGracefully().sync();
    		}
    	
    	}
    
    }
    
    
  4. 客户端ClientHandler

    package com.xm.netty.demo02;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.util.CharsetUtil;
    import io.netty.util.ReferenceCountUtil;
    
    public class ClientHandler extends ChannelHandlerAdapter {
    	
    	@Override
    	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    		
    		
    		try {
    			
    			ByteBuf in = (ByteBuf) msg;
    			String str = in.toString(CharsetUtil.UTF_8);
    			System.out.println("Client:"+str);
    			
    		} finally {
    			ReferenceCountUtil.release(msg);
    		}
    	}
    	
    	@Override
    	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    		cause.printStackTrace();
    		ctx.close();
    	}
    	
    	@Override
    	public void channelActive(ChannelHandlerContext ctx) throws Exception {
    		System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())+"  已连接上服务器!");
    	}
    	
    
    }
    
    
  5. 添加依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.xm</groupId>
      <artifactId>netty</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <dependencies>
    	  <dependency>
    	    <groupId>io.netty</groupId>
    	    <artifactId>netty-all</artifactId>
    	    <version>5.0.0.Alpha2</version>
    	</dependency>
      </dependencies>
    </project>
    
  6. 预期结果

    1)服务器

    2018-10-11T18:37:19.857一个客户端连接!

    Server:2018-10-11T18:37:19.855---- 10<<<

    Server:2018-10-11T18:37:20.377---- 11<<<

    Server:2018-10-11T18:37:20.877---- 12<<<

    Server:2018-10-11T18:37:21.378---- 13<<<

    Server:2018-10-11T18:37:21.879---- 14<<<

    Server:2018-10-11T18:37:22.379---- 15<<<

    Server:2018-10-11T18:37:22.879---- 16<<<

    Server:2018-10-11T18:37:23.38---- 17<<<

    Server:2018-10-11T18:37:23.881---- 18<<<

    Server:2018-10-11T18:37:24.382---- 19<<<

    (2)客户端

    2018-10-11T18:37:19.855 已连接上服务器!

    Client:服务器返回--->2018-10-11T18:37:19.855---- 10<<<

    Client:服务器返回--->2018-10-11T18:37:20.377---- 11<<<

    Client:服务器返回--->2018-10-11T18:37:20.877---- 12<<<

    Client:服务器返回--->2018-10-11T18:37:21.378---- 13<<<

    Client:服务器返回--->2018-10-11T18:37:21.879---- 14<<<

    Client:服务器返回--->2018-10-11T18:37:22.379---- 15<<<

    Client:服务器返回--->2018-10-11T18:37:22.879---- 16<<<

    Client:服务器返回--->2018-10-11T18:37:23.38---- 17<<<

    Client:服务器返回--->2018-10-11T18:37:23.881---- 18<<<

    Client:服务器返回--->2018-10-11T18:37:24.382---- 19<<<

  7. 实际结果

    (1)服务器

    2018-10-11T18:35:40.988一个客户端连接!
    Server:2018-10-11T18:35:40.986---- 10<<<2018-10-11T18:35:41.01---- 11<<<2018-10-11T18:35:41.01---- 12<<<2018-10-11T18:35:41.01---- 13<<<2018-10-11T18:35:41.01---- 14<<<2018-10-11T18:35:41.01---- 15<<<2018-10-11T18:35:41.01---- 16<<<2018-10-11T18:35:41.01---- 17<<<2018-10-11T18:35:41.01---- 18<<<2018-10-11T18:35:41.01---- 19<<<

    (2)客户端

    2018-10-11T18:35:40.986 已连接上服务器!
    Client:服务器返回--->2018-10-11T18:35:40.986---- 10<<<2018-10-11T18:35:41.01---- 11<<<2018-10-11T18:35:41.01---- 12<<<2018-10-11T18:35:41.01---- 13<<<2018-10-11T18:35:41.01---- 14<<<2018-10-11T18:35:41.01---- 15<<<2018-10-11T18:35:41.01---- 16<<<2018-10-11T18:35:41.01---- 17<<<2018-10-11T18:35:41.01---- 18<<<2018-10-11T18:35:41.01---- 19<<<

posted @ 2018-10-12 19:20  零度微笑  阅读(353)  评论(0编辑  收藏  举报