Netty框架中文编码(二)

2023-04-12


netty实战

  • 1. 背景
  • 2. 思路
  • 3. 实现
  • 4. 日志分析
  • 5. 总结

1. 背景


我在上一篇文章中提到,假如针对老系统升级,面向的客户端是不同的主体,并且因为各种原因出现了编码不一致的问题(实际情况下很难出现的场景),那么我们该如何处理?之前我想到一种办法是使用Nginx代理stream,但是经过验证不可行。后边我还有一种想法是通过程序来实现,根据对端的IP来指定不同的编码方式,采用配置化的方式实现。此种方式有待于进一步学习动态handler来进行验证。今天我就简单记录下实战情况。


2. 思路


  • 初始化initChannel时,先获取客户端IP
  • 根据客户端IP,动态实现不同编码

3. 实现


  • handler
public class CodeHandler extends ChannelInboundHandlerAdapter {
	public static final Logger log = LoggerFactory.getLogger(CodeHandler.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("服务端接收消息是:{}", msg);
        ctx.write(msg);
    }
	
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }
    
    @Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		log.info("exceptionCaught: " + cause.getLocalizedMessage());
	}
}
  • server
public class CodeServer {
	public static final Logger log = LoggerFactory.getLogger(CodeServer.class);
    private final String ip = "192.168.0.118";
    private final String port = "8001";

    public void init(){
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap bs = new ServerBootstrap();
        bs.group(bossGroup, workerGroup);
        bs.channel(NioServerSocketChannel.class);
        bs.childHandler(new ChannelInitializer(){
            @Override
            protected void initChannel(Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
                
                String remoteAddress = ch.remoteAddress().toString();
                log.info("远程地址:" + ch.remoteAddress().toString());
                if (remoteAddress.contains("192.168.0.118")) {
                	log.info("UTF-8编码");
                	pipeline.addLast(new StringDecoder(Charset.forName("UTF-8")));
                	pipeline.addLast(new StringEncoder(Charset.forName("UTF-8")));
				} else {
					log.info("GBK编码");
					pipeline.addLast(new StringDecoder(Charset.forName("GBK")));
					pipeline.addLast(new StringEncoder(Charset.forName("GBK")));
				}
                log.info("添加业务handler");
                pipeline.addLast(new CodeHandler());
            }
        });

        try {
            ChannelFuture channelFuture = bs.bind(ip, Integer.parseInt(port)).sync();
            log.info("Netty Server 启动成功! Ip: " + channelFuture.channel().localAddress().toString() + " ! ");

            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
  • 客户端模拟单元测试
public class CodeClient {
	
	public static final Logger log = LoggerFactory.getLogger(CodeClient.class);

	public void connect(int port, String host) throws InterruptedException {
		EventLoopGroup group = new NioEventLoopGroup();
		
		Bootstrap bootstrap = new Bootstrap();
		bootstrap.group(group)
		    .channel(NioSocketChannel.class)
		    .option(ChannelOption.TCP_NODELAY, true)
		    .handler(new ChannelInitializer() {
		    	@Override
	            protected void initChannel(NioSocketChannel ch) throws Exception {
	                final ChannelPipeline pipeline = ch.pipeline();
	                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
	                // 不同内网机器,实验时灵活切换
	                // 比如192.168.0.118为UTF-8,192.168.0.105为GBK
	                //pipeline.addLast(new StringEncoder(Charset.forName("UTF-8")));
	                pipeline.addLast(new StringEncoder(Charset.forName("GBK")));
	            }
		    });
		
		ChannelFuture future = bootstrap.connect("192.168.0.118", 8001).sync();
		future.addListener(new ChannelFutureListener() {
			public void operationComplete(ChannelFuture future) throws Exception {
				future.channel().writeAndFlush("你好");
			}
		});
		
		future.syncUninterruptibly();
		
		future.channel().closeFuture().sync();
	}
	
	public static void main(String[] args) throws InterruptedException {
		new CodeClient().connect(8001, "192.168.0.118");
	}
}

4. 日志分析


  • 192.168.0.118日志记录
    可以看到后台接收6B,为UTF-8编码。
10:43:08.021 [nioEventLoopGroup-3-4] INFO com.ll.demo2.CodeServer - 远程地址:/192.168.0.118:5756
10:43:08.021 [nioEventLoopGroup-3-4] INFO com.ll.demo2.CodeServer - UTF-8编码
10:43:08.021 [nioEventLoopGroup-3-4] INFO com.ll.demo2.CodeServer - 添加业务handler
10:43:08.022 [nioEventLoopGroup-3-4] INFO io.netty.handler.logging.LoggingHandler - [id: 0xbe4fd2ce, L:/192.168.0.118:8001 - R:/192.168.0.118:5756] REGISTERED
10:43:08.022 [nioEventLoopGroup-3-4] INFO io.netty.handler.logging.LoggingHandler - [id: 0xbe4fd2ce, L:/192.168.0.118:8001 - R:/192.168.0.118:5756] ACTIVE
10:43:08.053 [nioEventLoopGroup-3-4] INFO io.netty.handler.logging.LoggingHandler - [id: 0xbe4fd2ce, L:/192.168.0.118:8001 - R:/192.168.0.118:5756] READ: 6B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| e4 bd a0 e5 a5 bd                               |......          |
+--------+-------------------------------------------------+----------------+
10:43:08.053 [nioEventLoopGroup-3-4] INFO com.ll.demo2.CodeHandler - 服务端接收消息是:你好
10:43:08.054 [nioEventLoopGroup-3-4] INFO io.netty.handler.logging.LoggingHandler - [id: 0xbe4fd2ce, L:/192.168.0.118:8001 - R:/192.168.0.118:5756] WRITE: 6B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| e4 bd a0 e5 a5 bd                               |......          |
+--------+-------------------------------------------------+----------------+
10:43:08.054 [nioEventLoopGroup-3-4] INFO io.netty.handler.logging.LoggingHandler - [id: 0xbe4fd2ce, L:/192.168.0.118:8001 - R:/192.168.0.118:5756] READ COMPLETE
10:43:08.054 [nioEventLoopGroup-3-4] INFO io.netty.handler.logging.LoggingHandler - [id: 0xbe4fd2ce, L:/192.168.0.118:8001 - R:/192.168.0.118:5756] FLUSH
  • 192.168.0.105日志记录
    可以看到后台接收4B,为GBK编码。
10:41:54.537 [nioEventLoopGroup-3-3] INFO com.ll.demo2.CodeServer - 远程地址:/192.168.0.105:49630
10:41:54.537 [nioEventLoopGroup-3-3] INFO com.ll.demo2.CodeServer - GBK编码
10:41:54.537 [nioEventLoopGroup-3-3] INFO com.ll.demo2.CodeServer - 添加业务handler
10:41:54.538 [nioEventLoopGroup-3-3] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9da24e21, L:/192.168.0.118:8001 - R:/192.168.0.105:49630] REGISTERED
10:41:54.538 [nioEventLoopGroup-3-3] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9da24e21, L:/192.168.0.118:8001 - R:/192.168.0.105:49630] ACTIVE
10:41:54.560 [nioEventLoopGroup-3-3] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9da24e21, L:/192.168.0.118:8001 - R:/192.168.0.105:49630] READ: 4B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| c4 e3 ba c3                                     |....            |
+--------+-------------------------------------------------+----------------+
10:41:54.560 [nioEventLoopGroup-3-3] INFO com.ll.demo2.CodeHandler - 服务端接收消息是:你好
10:41:54.561 [nioEventLoopGroup-3-3] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9da24e21, L:/192.168.0.118:8001 - R:/192.168.0.105:49630] WRITE: 4B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| c4 e3 ba c3                                     |....            |
+--------+-------------------------------------------------+----------------+
10:41:54.561 [nioEventLoopGroup-3-3] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9da24e21, L:/192.168.0.118:8001 - R:/192.168.0.105:49630] READ COMPLETE
10:41:54.561 [nioEventLoopGroup-3-3] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9da24e21, L:/192.168.0.118:8001 - R:/192.168.0.105:49630] FLUSH

5. 总结


日志对比之后,发现可以根据不同IP区分开,并且中文编解码都正常。这样就解决了面对不同客户端主体的时候,可以进行编码的灵活配置了。




本文仅代表作者观点,版权归原创者所有,如需转载请在文中注明来源及作者名字。

免责声明:本文系转载编辑文章,仅作分享之用。如分享内容、图片侵犯到您的版权或非授权发布,请及时与我们联系进行审核处理或删除,您可以发送材料至邮箱:service@tojoy.com