netty源码分析(二十四)TCP粘包与拆包实例演示及分析

来源:互联网 发布:单片机控制方案 编辑:程序博客网 时间:2024/05/21 11:08

关于粘包与拆包的概念这里不再熬术,下面举一个粘包的例子:
客户端启动的时候向服务端写入了10条消息,然后服务端接收到消息之后,回写客户端一条UUID,客户端打印服务端发过来的UUID
MyServer:

public class MyServer {    public static void main(String[] args) throws InterruptedException {        EventLoopGroup bossGroup = new NioEventLoopGroup(1);        EventLoopGroup workerGroup = new NioEventLoopGroup();        try{            ServerBootstrap serverBootstrap = new ServerBootstrap();            serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)                    .childHandler(new MyServerInitializer());            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();            channelFuture.channel().closeFuture().sync();        }finally{            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }}

MyClientIniatializer:

public class MyClientIniatializer extends ChannelInitializer<SocketChannel> {    @Override    protected void initChannel(SocketChannel ch) throws Exception {        ChannelPipeline pipline = ch.pipeline();        pipline.addLast(new MyClientHandler());    }}

MyServerHandler:

public class MyServerHandler extends SimpleChannelInboundHandler<ByteBuf> {    private int  count ;    @Override    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {        byte[] buffer = new byte[msg.readableBytes()] ;        msg.readBytes(buffer);//注意buffer的长度必须和msg.readableBytes()一样,否则报错,这是netty规定的        String message = new String(buffer, Charset.forName("utf-8"));        System.out.println("服务端接收到的消息:"+message);        System.out.println("服务端接收到的消息数量:"+(++this.count));        ByteBuf responseMessage = Unpooled.copiedBuffer(UUID.randomUUID().toString(),Charset.forName("utf-8"));        ctx.writeAndFlush(responseMessage);    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        cause.printStackTrace();        ctx.close();    }}

Myclient:

public class Myclient {    public static void main(String[] args) throws InterruptedException {        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();        try {            Bootstrap bootstrap = new Bootstrap();            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new MyClientIniatializer());            ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();            channelFuture.channel().writeAndFlush("hello");            channelFuture.channel().closeFuture().sync();        } finally {            eventLoopGroup.shutdownGracefully();        }    }}

MyClientIniatializer:

public class MyClientIniatializer extends ChannelInitializer<SocketChannel> {    @Override    protected void initChannel(SocketChannel ch) throws Exception {        ChannelPipeline pipline = ch.pipeline();        pipline.addLast(new MyClientHandler());    }}

MyClientHandler:

public class MyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {    private int count;    @Override    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {        byte[] buffer = new byte[msg.readableBytes()];        msg.readBytes(buffer);        String message = new String(buffer,Charset.forName("utf-8"));        System.out.println("客户端接收到的消息内容:"+message);        System.out.println("客户端接收到的消息数量:"+(++this.count));    }    @Override    public void channelActive(ChannelHandlerContext ctx) throws Exception {        for(int i = 0;i <10;i++){            ByteBuf buffer  = Unpooled.copiedBuffer("sent from client",Charset.forName("utf-8"));            ctx.writeAndFlush(buffer);        }    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        super.exceptionCaught(ctx, cause);        ctx.close();    }}

服务端打印结果:

服务端接收到的消息:sent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from client服务端接收到的消息数量:1

客户端打印结果:

客户端接收到的消息内容:8c260c09-8a9d-4491-9bf7-ff5c5c8f790c客户端接收到的消息数量:1

很多人认为客户端应该收到10条UUID才对,但是这里协议进行了粘包,将客户端的10条消息作为一条消息发给我服务端,才导致服务端只打印了一天消息(10条客户端消息的集合)而且只接受了一次,因此服务端打印的接收数量是1。

此时我们把客户端关闭,然后重新连接服务端,我们重复2次这个过程。
服务端打印结果:

服务端接收到的消息:sent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from clientsent from client服务端接收到的消息数量:1服务端接收到的消息:sent from client服务端接收到的消息数量:1服务端接收到的消息:sent from client服务端接收到的消息数量:2服务端接收到的消息:sent from clientsent from clientsent from client服务端接收到的消息数量:3服务端接收到的消息:sent from clientsent from client服务端接收到的消息数量:4服务端接收到的消息:sent from clientsent from clientsent from client服务端接收到的消息数量:5服务端接收到的消息:sent from client服务端接收到的消息数量:1服务端接收到的消息:sent from client服务端接收到的消息数量:2服务端接收到的消息:sent from clientsent from clientsent from clientsent from client服务端接收到的消息数量:3服务端接收到的消息:sent from clientsent from client服务端接收到的消息数量:4服务端接收到的消息:sent from clientsent from client服务端接收到的消息数量:5

疑问是为什么MyServerHandler里边的count会重新从1开始?
其实这里的MyServerInitializer每当有一个客户端连接上来的时候都会新建一个MyServerHandler,也就会初始化MyServerHandler的count,因此出现这样的结果。
这样的现象是tcp协议的一部分,我们在使用netty的时候可以通过编解码器来解决tcp粘包和拆包的问题。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝买家恶意差评怎么办 淘宝评价完了忘截图了怎么办 12306app登录不上怎么办 淘宝换绑支付宝失败怎么办 淘宝和手机不兼容怎么办 换号之后微信怎么办 手机不兼容的应用程序怎么办 微信版本低登录不了怎么办 软件与系统不兼容怎么办 软件与手机系统不兼容怎么办 qq和手机不兼容怎么办 来个软件不兼容怎么办 安卓8.0不兼容app怎么办 两条内存不兼容怎么办 王者荣耀软件不兼容怎么办 冒险岛不兼容win7怎么办 百度网盘手机号换了怎么办 破解版游戏闪退怎么办 安卓手机软件不兼容怎么办 安卓8.0软件闪退怎么办 游戏与手机系统不兼容怎么办 耳机和手机不兼容怎么办 软件和手机不兼容怎么办 小米6开关键失灵怎么办 同步助手下载不了微信旧版本怎么办 闲鱼退货卖家拒收怎么办 闲鱼把联系人删了怎么办 闲鱼付款了卖家不发货怎么办 红米4c卡怎么办 如果买鞋子买到假的怎么办 猎趣永久封号钱怎么办 支付宝换绑定手机后怎么办 为什么回收站的删除键不见了怎么办 微信在异地登录怎么办 支付宝帐号被冻结怎么办 进不了路由器设置页面怎么办 支付宝支付密码忘记了怎么办 淘宝忘记登录密码了怎么办 手机换卡了微信怎么办 淘宝退款成功后收到货怎么办 没收到货退款商家不处理怎么办