Netty:模拟粘包

一、TCP的粘包拆包问题

    Tcp底层协议保证了发数据包的顺序,并没有保证每一次会发一个完整的包。

   下面用图来表示粘包,拆包的一种情况:

   假设客户端向服务端发送了两个请求包(data1,data2),服务端收到这两个包的情况是无     法预测的。

   

  二、Netty模拟粘包

Server:

/********************************************************************
 * Netty 学习
 ********************************************************************
 */
package com.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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;

/**
 *
 * @author Jack Lei
 * @email 895896736@qq.com
 * @date 2016年3月13日 下午3:07:12
 */
public class Server {
	final static short	packetId	= 1001;

	public Server(int port) {
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup work = new NioEventLoopGroup();

		ServerBootstrap boot = new ServerBootstrap();
		boot.group(boss, work)
			.channel(NioServerSocketChannel.class)
			.option(ChannelOption.TCP_NODELAY, true)
			.childHandler(new ChannelInitializer<SocketChannel>() {

				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {

						@Override
						public void channelRead(ChannelHandlerContext ctx,
												Object msg) throws Exception {
							ByteBuf buf = (ByteBuf) msg;
							short packetId = buf.readShort();
							if (packetId == Server.packetId) {
								byte[] bytes = new byte[buf.readableBytes()];
								buf.readBytes(bytes);
								String str = new String(bytes);
								System.out.println("PacketId = " + packetId + ", body = " + str);
							}
						}

					});
				}
			});
		try {

			ChannelFuture future = boot.bind(port).sync();
			future.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			boss.shutdownGracefully();
			work.shutdownGracefully();
		}
	}

	public static void main(String[] args) {
		new Server(8090);
	}
}
Client

/********************************************************************
 * 
 * Netty 学习
 ********************************************************************
 */
package com.netty;

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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 *
 * @author Jack Lei
 * @email 895896736@qq.com
 * @date 2016年3月13日 下午3:19:48
 */
public class ClientTest {
	final short	packetId	= 1001;

	public ClientTest(String host, int port) {
		EventLoopGroup work = new NioEventLoopGroup();
		Bootstrap boot = new Bootstrap();
		boot.group(work)
			.channel(NioSocketChannel.class)
			.handler(new ChannelInitializer() {
				@Override
				protected void initChannel(Channel ch) throws Exception {
					ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {

						@Override
						public void channelActive(ChannelHandlerContext ctx) throws Exception {
							for (int i = 0; i < 100; i++) {
								ByteBuf buf = Unpooled.buffer();
								buf.writeShort(packetId);
								String msg = "返回信息。";
								buf.writeBytes(msg.getBytes());
								ctx.writeAndFlush(buf);
							}
						}

						@Override
						public void channelRead(ChannelHandlerContext ctx,
												Object msg) throws Exception {
							super.channelRead(ctx, msg);
						}

					});
				};
			});
		try {
			ChannelFuture future = boot.connect(host, port).sync();
			future.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			work.shutdownGracefully();
		}
	}

	public static void main(String[] args) {
		new ClientTest("127.0.0.1", 8090);
	}
}


  三、测试结果:

   出现粘包的情况后,服务端如果不做处理粘包拆包处理,就无法正确的把包解码,导致了客户端收不到相应的返回包。关于粘包,拆包的解决办法,将会在下一篇写出。


    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值