在开发 Netty 学习中,遇到了这样一个问题:我通过 Netty 提供的发送数据的三种方式发送数据至远端,发送端没有抛出任何异常,但是远端就是没有收到数据。发送数据的的三种方式如下:

    channelHandlerContext.writeAndFlush("Netty test");
    channel.writeAndFlush("Netty test");
    channelPipeline.writeAndFlush("Netty test");
    这种写法应该是没问题,因为已经简单得想弄出点问题都很难,那问题出现在哪里了?各种搜索。。。

    网上很多例子都是类似于:

    channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("Netty test", CharsetUtil.UTF_8))
    ......

    用这种方式发送数据没问题的。

    为什么了?

    从前面的几种发生方式来看,只是发送的内容的类型不一样:

    "Netty test"—— 字符串对象

    Unpooled.copiedBuffer("Netty test", CharsetUtil.UTF_8)—— 字节数组

    我们都知道一个准则:在网络上传播的数据都是字节(其实也就是二进制数据)类型。我们如果直接向网络流里面写入一个对象(如:String对象),是无法传输的。只有将对象序列化(转换为可以传输的字节类型)之后,才可以进行传输。所以问题的根源就很清楚了,需要把字符串("Netty test")转换成字节进行传输。那另一个问题又来了:

    怎么把 String 转换成 字节了?

    这种小问题 Netty 肯定是早就想到了,它预设置了很多好用的 ChannelHandler,其中就有一个 StringEncoder():将 String 转换为可以传输的字节类型。相对应的 StringDecoder():将字节流转换为 String 对象。所以我们只需要在引导应用程序的时候,在 ChannelPipeLine(包含每一个 Channel 所需要用到的所有 ChannelHandler)中添加 StringEncoder 和 StringDecoder 即可,如下样例

bootStrap.handler(new ChannelInitializer() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline cpl = ch.pipeline();
                            cpl.addLast(new LoggingHandler(LogLevel.DEBUG));
                            cpl.addLast(new StringEncoder());//对 String 对象自动编码,属于出站站处理器
                            cpl.addLast(new StringDecoder());//把网络字节流自动解码为 String 对象,属于入站处理器
                            //其他需要使用的 ChannelHandler
                            ......
                        }
                    });