`
bastengao
  • 浏览: 150436 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

netty frame 封包解决方法

    博客分类:
  • java
阅读更多
最近有做毕业设计,需要大量用到网络相关的东西,之前也用socket 写过一些东西,但是感觉直接用socket太费事了。所以就利用现成的框架工具,来做了。找一些东西,最后选择用netty。 netty 是一个异步网络编程框架。他在发送数据和接收数据都是异步的。他提供了许多扩展,利用他可以省好多事。
利用socket或者基于流的传输协议会出现一些问题。netty的官方教程中也提到了。原文是这样的:
引用
In a stream-based transport such as TCP/IP, received data is stored into a socket receive buffer. Unfortunately, the buffer of a stream-based transport is not a queue of packets but a queue of bytes. It means, even if you sent two messages as two independent packets, an operating system will not treat them as two messages but as just a bunch of bytes. Therefore, there is no guarantee that what you read is exactly what your remote peer wrote. For example, let us assume that the TCP/IP stack of an operating system has received three packets:

+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+

Because of this general property of a stream-based protocol, there's high chance of reading them in the following fragmented form in your application:

+----+-------+---+---+
| AB | CDEFG | H | I |
+----+-------+---+---+

Therefore, a receiving part, regardless it is server-side or client-side, should defrag the received data into one or more meaningful frames that could be easily understood by the application logic. In case of the example above, the received data should be framed like the following:

+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+


小弟不才,原文大概的意思是这样的:
引用
在例如 TCP/IP 这样基于流的传输过程中,接收到的数据是存储在socket接收缓冲区中。不幸的是,基于流的缓冲区里的顺序不是按照包的顺序,而是按照字节的顺序。也就是说,即使你通过两个独立的包发送了两个消息,但操作系统不会把他们当做两个独立的消息,而是字节串。因此,你读取到的是与远端写的一致性是无法保证的。例如,让我们假设有这样的操作系统已经接收到的TCP/IP数据包的栈:

+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+

因为基于流协议的通常特性,很可能应用程序以下面的顺序读取数据:

+----+-------+---+---+
| AB | CDEFG | H | I |
+----+-------+---+---+

因此,在接收数据的时候,无论是服务端还是客户端,都应该将接收到的数据组织成有意义的帧(frame),从而更简单的处理应用逻辑。之前的例子,接收到的数据应该被封成这样的帧:

+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+



我在开发过程中也确实遇到这样的问题,netty的官方教程也在接下来讲了解决方法。但可能为让读者更深刻的理解netty,用的是比较底层的api。其实netty应对 拆包与组包,已经有解决方法。netty 有一个包 org.jboss.netty.handler.codec.frame ,这个包里面有三种解决方法,都是对 netty 的 codec 进行的扩展。其中 1.DelimiterBasedFrameDecoder 是利用分隔符来进行包的界定;2.FixedLengthFrameDecoder 是利用固定的长度来进行包的界定;3.LengthFieldBasedFrameDecoder 和 LengthFieldPrepender 是利用在发送数据的时候在里面加上头字段,头字段里面包含了包的长度。
这三种方面我用到了其中两种(DelimiterBasedFrameDecoder 和 LengthFieldBasedFrameDecoder)。

举一个 LengthFieldBasedFrameDecoder 的例子
服务器端
ServerBootstrap serverBootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
        serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() throws Exception {
                ChannelPipeline pipeline = org.jboss.netty.channel.Channels.pipeline();
                pipeline.addLast(Constants.LOGGING_HANDLER, new LoggingHandler());
                pipeline.addLast(Constants.UP_FRAME_HANDLER, new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
                pipeline.addLast(Constants.DOWN_FRAME_HANDLER, new LengthFieldPrepender(2, false));
                //add customer handler
                pipeline.addLast("myHandler", new ServerMessageHandler());
                return pipeline;
            }
        });
        serverBootstrap.bind(new InetSocketAddress(9999));


客户端
 ClientBootstrap clientBootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
        clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            @Override
            public ChannelPipeline getPipeline() throws Exception {
                ChannelPipeline pipeline = org.jboss.netty.channel.Channels.pipeline();
                pipeline.addLast(Constants.LOGGING_HANDLER, new LoggingHandler());
                pipeline.addLast(Constants.UP_FRAME_HANDLER, new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
                pipeline.addLast(Constants.DOWN_FRAME_HANDLER, new LengthFieldPrepender(2, false));
                //add customer handler
                clientMessageHandler = new ClientMessageHandler();
                pipeline.addLast("myHandler", clientMessageHandler);
                return pipeline;
            }
        });

        clientBootstrap.connect(new InetSocketAddress(9999));
2
0
分享到:
评论
1 楼 beykery 2013-12-27  
嗯分析的不错。我们也是采用类似LengthFieldBasedFrameDecoder 方式分包的,不过我们重写了,因为觉得源代码还是处理的太复杂,这个逻辑其实是这样:
   public ByteBuf translateFrame(ByteBuf readBuffer) throws LimitExedeedException, InvalidDataException
    {
        while (readBuffer.isReadable())
        {
            switch (status)
            {
                case STATUS_H:
                    h = readBuffer.readByte();
                    status = STATUS_L;
                    break;
                case STATUS_L:
                    l = readBuffer.readByte();
                    final int blen = (0x0000ff00 & (h <<) | (0x000000ff & l);
                    if (context != null)
                    {
                        if (blen <= 0 || blen > maxFrameSize)
                        {
                            throw new LimitExedeedException("帧长度非法:" + h + "/" + l + ":" + blen);
                        }
                    }
                    incompleteframe = PooledByteBufAllocator.DEFAULT.buffer(blen + 8 + 2);
                    incompleteframe.writeShort(blen);
                    status = STATUS_C;
                    break;
                case STATUS_C:
                    int len = incompleteframe.writableBytes() - 8;
                    len = len < readBuffer.readableBytes() ? len : readBuffer.readableBytes();
                    //incompleteframe.writeBytes(readBuffer, len);
                    if (readBuffer.hasMemoryAddress())
                    {
                        PlatformDependent.copyMemory(readBuffer.memoryAddress() + readBuffer.readerIndex(), incompleteframe.memoryAddress() + incompleteframe.writerIndex(), len);
                    } else if (readBuffer.hasArray())
                    {
                        PlatformDependent.copyMemory(readBuffer.array(), readBuffer.arrayOffset() + readBuffer.readerIndex(), incompleteframe.memoryAddress() + incompleteframe.writerIndex(), len);
                    }
                    incompleteframe.writerIndex(incompleteframe.writerIndex() + len);
                    readBuffer.readerIndex(readBuffer.readerIndex() + len);
                    if ((incompleteframe.writableBytes() - <= 0)
                    {
                        status = STATUS_H;
                        return incompleteframe;
                    }
                    break;
            }
        }
        return null;
    }

相关推荐

    Netty粘包分包现象及解决方案实战,防socket攻击

    Netty粘包分包现象及解决方案实战,防socket攻击水。

    使用Netty解决TCP粘包和拆包问题过程详解

    解决TCP粘包和拆包问题的方法有多种,例如: 1. 消息定长,例如每个报文的大小固定为20个字节,如果不够,空位补空格。 2. 在包尾增加回车换行符进行切割。 3. 将消息分为消息头和消息体,消息头中包含表示消息总...

    netty拆包粘包解决方案示例

    Netty提供了多种解决拆包粘包问题的方法: 1. ByteBufUtil:Netty提供了ByteBufUtil工具类,可以用来读取和写入字节。它支持读取固定长度、变长长度(如前缀长度)的消息。 2. ByteToMessageDecoder:这是Netty...

    使用Netty搭建WebSocket服务器,可修改单包大小限制

    通过这种方式,我们就成功地在Netty中修改了WebSocket服务器的单包大小限制,从而解决了不能发送大数据包的问题。这种方法对于需要传输大量数据的场景,如在线游戏、实时视频流或大数据交换等,是非常有用的。同时,...

    netty解析报文,解决粘包拆包

    注:下载前请查看本人博客文章,看是否...里面包含模拟TCP客户端发送报文工具,硬件厂商提供的协议,服务端(springboot+netty)解析报文源码,源码里整合了redis,不需要可自行删除,如有需要客户端代码,可联系我。

    netty websocket通讯接收数据不完整问题

    这是一个java web项目集成了netty websocket的...初始化握手对象时指定了maxFramePayloadLength 的长度、以及通过配置netty内置解码器处理数据半包等方法,均无效。以下是终极解决办法,供大家参考和解决这样的问题。

    跟闪电侠学Netty:Netty即时聊天实战与底层原理-book-netty.zip

    10. **问题排查与调试**:提供Netty应用中常见问题的解决方法和调试技巧,帮助开发者快速定位和解决问题。 本书的源代码位于`book-netty-master`目录下,包含了书中的示例代码,读者可以通过阅读和运行这些代码,...

    Netty粘包拆包解决方案.docx

    总的来说,Netty提供的解码器机制使得开发者无需深入理解TCP底层细节,也能有效地解决粘包和拆包问题,提高了网络通信的可靠性和效率。通过选择合适的解码器并合理配置,我们可以构建出健壮的网络应用。

    Netty断线重连解决方案.docx

    Netty 断线重连解决方案 Netty 是一个高性能的 NIO 框架,用于构建高性能的网络应用程序。然而,在使用 Netty 实现长连接服务时,可能会遇到断线的问题,即客户端和服务端之间的连接断开。这种情况可能是由于网络...

    Netty实战 电子版.pdf_java_netty_服务器_

    《Netty实战》是针对Java开发者的一本技术指南,它深入介绍了如何利用Netty这个高性能、异步事件驱动的网络应用程序框架来构建高效且可扩展的网络应用。Netty不仅简化了网络编程的复杂性,还提供了丰富的特性和组件...

    netty-netty-4.1.69.Final.tar.gz

    4. 文档:包括API文档、用户指南和开发者手册,帮助理解Netty的工作原理和使用方法。 5. 测试用例:用于验证Netty功能的测试代码。 在实际开发中,开发者可以根据需求选择引入对应的Netty模块,通过编写...

    Netty实战.epub_netty实战epub_netty实战epub_netty_

    《Netty实战》这本书是针对Java网络编程框架Netty的一本深入实践教程,旨在帮助读者掌握Netty的核心特性和实际应用。Netty是一款高性能、异步事件驱动的网络应用程序框架,广泛应用于各种分布式系统、微服务架构以及...

    Netty (netty-netty-5.0.0.Alpha2.tar.gz)

    Netty (netty-netty-5.0.0.Alpha2.tar.gz)是一个 NIO 客户端服务器框架,可以快速轻松地开发协议服务器和客户端等...因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

    Netty进制转换乱码问题

    在本文中,我们将深入探讨Netty中的进制转换和字符编码,并提供解决方案。 首先,我们要明白Netty作为一个高性能的网络应用框架,它本身并不直接处理字符编码,而是通过ByteBuf对象来存储和传输字节流。ByteBuf是...

    netty4-netty5.rar

    ChannelHandlerAdapter 4.X版本和5.X版本的差别很大。ChannelRead是属于5.X版本的4.X版本没有这个方法,所以如果要用ChannelRead。可以更换5.X版本的Netty。

    Netty基础,用于学习Netty,参考黑马程序员的netty教程

    Netty基础,用于学习Netty,参考黑马程序员的netty教程

    Netty进阶之路-跟着案例学Netty

    《Netty进阶之路-跟着案例学Netty》是由知名技术专家李林峰撰写的一本专为Java开发者深入理解Netty框架而准备的书籍。这本书旨在通过实例教学,帮助读者全面掌握Netty的核心特性和实战技巧,提升网络编程的能力。 ...

    Netty 教程 Netty权威指南

    5. **EventLoop 和 EventLoopGroup**:EventLoop 负责执行 ChannelHandler 中的事件处理方法,EventLoopGroup 是 EventLoop 的集合,负责管理和分配 EventLoop。 **二、Netty 的高级特性** 1. **零拷贝**:Netty ...

    最新netty中文文档chm版

    这个“最新Netty中文文档CHM版”为中国的开发者提供了一个方便的中文学习资源,解决了阅读英文原版文档时的语言障碍,使学习过程更为轻松。 Netty 的核心特性包括: 1. **高性能**: Netty 使用了Java NIO(非阻塞I...

Global site tag (gtag.js) - Google Analytics