如何解决netty发送字符串过长会产生截断问题

    在netty开发过程中我遇到过长的消息被分割成多个小消息的问题。如下图所示:

其实这两条消息应该是一条消息,它们两个才是一个完整的json字符串。查看代码原来发现少了对象编码与解码类!

Netty的消息传递都是基于流,通过ChannelBuffer传递的,消息Object需要转换成ChannelBuffer来传递。Netty本身已经提供了工具类:ObjectEncoder和ObjectDecoder。

可惜开发人员没有加。原来的代码是这的:

        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            ChannelFuture chFuture =new ServerBootstrap()
                    .group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline()
                    .addLast(new PushingChannelHandler());
                }
            })
            .bind(PORT).sync();
            if (chFuture.isSuccess()) {
                LGR.info("MessagePushingTCPServer started successfully!");
                chFuture.channel().closeFuture().sync();
            }

        } catch (Throwable e) {
            LGR.error("error occurred in MessagePushingTCPServer", e);
        } finally {
            Future<?> bossShutdownFuture = boss.shutdownGracefully();
            Future<?> workerShutdownFuture = worker.shutdownGracefully();
            try {
                bossShutdownFuture.await();
                workerShutdownFuture.await();
            } catch (InterruptedException e) {
                LGR.error("shutdown await interrupted by exception.");
            }
        }

注意其中红色代码部分并没有在ChannelPipeline注册ObjectEncoder和ObjectDecoder。

红色代码部分正确的代码是这样子的:

        ch.pipeline()
         .addLast(new ObjectEncoder())
         .addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)))
         .addLast(new PushingChannelHandler());

但这样改了子后会遇到我们以前的客户端兼容问题。我们已经发布的APP将全部不能收到推送,损失几乎不能接受。

后来我尝试更改ChannelOption终于可以支持长消息了,现将代码贴出,目前算是一种补救方案。

            ChannelFuture chFuture =new ServerBootstrap()
                    .group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(2048))
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline()
                    .addLast(new PushingChannelHandler());
                }
            })
            .bind(PORT).sync();

增加了一行设置ChannelOption的代码:

.childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(2048))

目前测试没有任何问题,可以满足我们公司的需求。但背后的原理目前我还不太明白。
时间: 2024-10-13 22:27:14

如何解决netty发送字符串过长会产生截断问题的相关文章

解决Window下文件名过长,导致无法删除,打开等问题

由于重装了Win8.1,在C盘会生成window.old的文件夹.本来想删除的,却出现文件名太长无法删除.那就改名呗,右键选择文件,我去,只有打开和发送选项,连属性选项都没有.当然打开和发送功能也不能正常使用. 那就用cmd来改名或删除呗,发现两个操作均由于文件名过长而失败. 由于当时没有截图,事后模拟一下,发现不能再现之前的情况: 后来google一个可行方案:可以使用文件短名来代替长长的文件名. cd C:\Windows\Vss\Writers\Application dir \x #就会

IDEA编译时报“常量字符串过长”问题

关于IDEA编译时报“常量字符串过长”的问题: 解决办法:File >> Settings >> Build,Execution,Deployment >> Compiler >>Java Compiler  将 Use compiler 改为 Eclipse 即可: 点击OK,重启Tomcat即可! 原文地址:https://www.cnblogs.com/abcdjava/p/12151544.html

解决DataSnap支持的Tcp长连接数受限的两种方法

如何解决DataSnap支持的Tcp长连接数受限的问题? 方案一: 采用代理服务器方式,基本流程为: 1.客户先连接代理服务器:2.获取可用的服务器IP和端口:3.关闭与代理服务器之间的连接:4.建立与可用服务器之间的连接.而且在第2步中可以实现负载均衡的配置与实现.博主最近对一个机房管理系统升级采用的就是此方案,学校(某一高新)公共机房现有机房50间左右,每间机房60台机器(标准配置),现有客户端3000台左右,以后肯定还要扩容更新的,故以5000个客户端为正常容量.因为要实时检测学生的的状态

C语言 realloc为什么要有返回值,realloc返回值详解/(解决任意长度字符串输入问题)。

在C语言操作中会用到大量的内存操作,其中很常用的一个是realloc(). 由字面意思可以知道,该函数的作用是用于重新分配内存. 使用方式如下: NewPtr=(数据类型*)realloc(OldPtr,MemSize) 其中OldPtr指向 待重新分配内存的指针. NewPtr指向 新分配空间的指针. MemSize为 分配后的空间大小. 该函数的使用涉及以下几个问题: 1.不同情况下的返回值 2.OldPtr指向的内存会不会自动释放 3.OldPtr和NewPtr分别是什么内容,他们有什么关

求两个字符串最长公共子串

一.问题描述: 最长公共子串 (LCS-Longest Common Substring) LCS问题就是求两个字符串最长公共子串的问题.比如输入两个字符串"ilovechina"和“chinabest”的最长公共字符串有"china",它们的长度是5. 二.解法 解法就是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0.然后求出对角线最长的1序列,其对应的位置就是最长匹配子串的位置.如下图: i   l   o  v  e  

两个字符串最长公共子串的问题

算法的基本思想: 当字符匹配的时候,不是简单的给相应元素赋上1,而是赋上其左上角元素的值加一. 我们用两个标记变量来标记矩阵中值最大的元素的位置,在矩阵生成的过程中来判断 当前生成的元素的值是不是最大的,据此来改变标记变量的值,那么到矩阵完成的时 候,最长匹配子串的位置和长度就已经出来了.===========================================================================程序:#include<string.h> #define

请求筛选模块被配置为拒绝包含的查询字符串过长的请求。

仔细观察,发现请求的url是酱紫的: http://localhost:58228/Account/Login?ReturnUrl=%2FAccount%2FLogin%3FReturnUrl%3D%252FAccount%252FLogin%253FReturnUrl%253 原来是Account/Login在return url里一直重复,难怪请求字符串过长呢! 检查web.config发现如下配置: <authorization> <deny users="?"

无线模块数据加密,反码校验,发送字符串&quot;ABCDEFGHIJKLMNOP&quot; LED频闪

[原帖必看,不然你看不懂本帖] 单片机编码 无线模块发送与接收 程序 [说明]:                        [发送端]: LED亮灭跟随发送状态 发送字符串"ABCDEFGHIJKLMNOP" 发送过程,用"春哥"的GBK码对字符串异或运算加密 数据校验:采用反码校验,先发送源码,再发送反码,抗干扰 [接收端] 接收加密的源码,用"春哥"的GBK码对字符串异或运算解密,得到源码 接收反码,反码与源码比较 接收字符串 判断字符串

多进程解决datasnap支持的tcp长连接数量少的问题

对于实时采集数据的项目,应用场景比如是这样的:5000客户端,每个客户端每隔500MS要给服务器上传一次数据. 大家知道,像INDY这种阻塞型的通信控件,所能支持的TCP长连接的一般地不能超过1000的数量(如果想要维持稳定运行的话). 原因是大家都晓得的,阻塞方式会为每一个SOCKET连接创建一个新的线程为之服务,而WINDOWS单个进程理论上允许最多的线程数量是2048个, 实际当中要少得多才行. 有人说可以用WINDOWS的IOCP通信模型解决,诚然!但IOCP编程过于复杂. 有人说,可以