您的位置:首页 > 新闻 > 资讯 > e福州便民服务自助终端_专业的建站公司服务_目前最靠谱的推广平台_企业网站搭建

e福州便民服务自助终端_专业的建站公司服务_目前最靠谱的推广平台_企业网站搭建

2024/12/23 6:10:04 来源:https://blog.csdn.net/weixin_46425661/article/details/144338006  浏览:    关键词:e福州便民服务自助终端_专业的建站公司服务_目前最靠谱的推广平台_企业网站搭建
e福州便民服务自助终端_专业的建站公司服务_目前最靠谱的推广平台_企业网站搭建

文章目录

  • 前言
  • 问题描述
  • 相关代码
  • 解决方法


前言

环境
JDK:64位 jdk1.8.0_201
Netty:4.1.39.Final

问题描述

项目中使用Netty接受客户端的消息,客户端为硬件设备,在接受数据后发送数据到服务端。
同时因为客户端没有联网,所以可能会因为开关机等原因导致时间不准确,因此需要服务端添加一个校验时间的操作,如果时间差距过大则发送重新设置时间的指令。

相关代码

@Slf4j
@Component
public class NettyServer {@Autowiredprivate SocketConfig socketConfig;private EventLoopGroup bossGroup = null;private EventLoopGroup workerGroup = null;public void start() throws Exception {bossGroup = new NioEventLoopGroup(1);workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(2048, 2048, 2048)).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new DeviceChannelInitHandler());//无关代码省略...} catch (Exception e) {log.info("netty异常:", e);} }...
}

处理器

@Slf4j
public class DeviceChannelInitHandler extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {...//使用自定义分割符customizeSplitHandler(socketChannel, true, "$");socketChannel.pipeline().addLast(new StringDecoder());// 添加自定义的业务处理器socketChannel.pipeline().addLast(new DeviceServiceHandler());socketChannel.pipeline().addLast(new StringEncoder());...}/*** 自定义分隔符处理器** @param socketChannel* @param stripDelimiter* @param split*/private static void customizeSplitHandler(SocketChannel socketChannel, boolean stripDelimiter, String split) {ByteBuf buffer = ByteBufAllocator.DEFAULT.heapBuffer(10);buffer.writeBytes(split.getBytes());socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(2048, stripDelimiter, buffer));}
}

业务处理器

@Slf4j
public class DeviceServiceHandler extends SimpleChannelInboundHandler<String> {/*** 解码协议(字符串转换)** @param ctx     the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}*                belongs to* @param dateStr the message to handle* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String dateStr) throws Exception {...//如果设备发送的时间和当前系统时间差距太大,则修正设备时间String sendDate = DateUtil.getStringCustomFormatByDate(new Date(), "yyyyMMddHHmmss");String command = "#SETTIME" + sendDate + "!$";//发送指令ctx.writeAndFlush(command);...}
}

解决方法

经过逐一排查,查看git的历史记录,发现原因是之前的同事将字符串编码器 StringEncoder 放在了业务处理器DeviceServiceHandler 的下面。

导致在数据发送时,业务处理器DeviceServiceHandler 会先处理数据,但此时数据还没有被编码为字节数据。由于 StringEncoder 还没有被调用,数据将以未编码的形式发送,这可能导致客户端无法正确解析数据,从而无法接收到正确的数据。

@Slf4j
public class DeviceChannelInitHandler extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {...customizeSplitHandler(socketChannel, true, "$");socketChannel.pipeline().addLast(new StringDecoder());//将字符串编码器 StringEncoder 放在业务处理器上面,客户端即可收到数据socketChannel.pipeline().addLast(new StringEncoder());socketChannel.pipeline().addLast(new DeviceServiceHandler());...}
}

如果对Netty中入站和出站处理器还不是很了解,可以看以下这篇文章:
Netty组件Handler & Pipeline


版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com