kotlin 项目中 Netty中使用MessagePack 传输 编码/解码

仍然需要注意的是,我使用的是Netty 5.x的版本。

另外我在程序代码中写了非常详细的注释,所以这里不再进行更多的说明。

发送器,编码

package com.goav.netty.Handler

import com.daveanthonythomas.moshipack.MoshiPack
import com.ftrd.flashlight.FileKt.LogUtils
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.MessageToByteEncoder
import io.netty.handler.codec.MessageToMessageCodec
import io.netty.handler.codec.MessageToMessageDecoder
import io.netty.handler.codec.MessageToMessageEncoder
import okio.BufferedSource
import okio.ByteString


/**
 *
 *@author: Jeff <[email protected]>
 * @time: 2018-05-16 15:10
 * @description:  发送器,编码
 * EncodeHandler 继承自 Netty 中的 MessageToMessageEncoder 类,
 * 并重写抽象方法 encode(ctx: ChannelHandlerContext?, msg: Any?, out: MutableList<Any>?)
 * 它负责将Object类型的POJO对象编码为byte数组,然后写入到ByteBuf中
 *
 */

internal class EncodeHandler : MessageToMessageEncoder<Any>() {
    override fun encode(ctx: ChannelHandlerContext?, msg: Any?, out: MutableList<Any>?) {
        // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        /*==========Convert an object to MessagePack format 对象转换为 essagePack ===================================================*/
//       data class MessagePackWebsitePlug(var compact: Boolean = true, var schema: Int = 0)
//        val moshiPack = MoshiPack()
//        val packed: BufferedSource = moshiPack.pack(MessagePackWebsitePlug())
//        println(packed.readByteString().hex())
        /*=============================================================*/
//        var moshiPack: MoshiPack = MoshiPack();
//        val packed: BufferedSource = moshiPack.pack(msg)
////        out!!.writeByte(packed.readUtf8CodePoint(),packed.readInt(),);//类型
////        out!!.writeByte(packed.readInt());//发送的内容长度
////        out!!.writeBytes(msg!!.bytes);//发送的内容
//        var objects: String = packed.readByteString().hex();
//        out!!.add(objects)
//        LogUtils.d("EncodeHandler", objects)
        /*msgpackToJson
        直接从MessagePack字节转换为JSON。由于在该过程中没有实例化对象,因此使用此方法进行最有效的实现。
        这使用FormatInterchange该类来匹配JsonReader和a的实现JsonWriter。如果您想将支持XML作为直接转换,
        您可以实现Moshi JsonReader和JsonWriter类,并使用FormatInterchange该类直接转换为其他格式。包含MessagePack数据的JSON表示的返回 String*/
        LogUtils.d("EncodeHandler", "msg="+msg.toString())
         var  bytes:ByteArray= ByteString.decodeHex(msg!!.toString()).toByteArray();
        var msgpackToJson:String= MoshiPack().msgpackToJson(bytes)
        out!!.add(msgpackToJson)
        LogUtils.d("EncodeHandler", "msgpackToJson="+msgpackToJson)

    }


}

接收器,解码

package com.ftrd.flashlight.nettys.handlers

import com.daveanthonythomas.moshipack.MoshiPack
import com.ftrd.flashlight.FileKt.LogUtils
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.MessageToMessageDecoder
import okio.BufferedSource
import okio.ByteString

/**
 * @author: Jeff <[email protected]>
 * @date:  2018-05-16 15:58
 * @description: 接收器,解码
 *
 * DecodeHandler 继承自 Netty 中的 MessageToMessageDecoder 类,
 * 并重写抽象方法 decode(ctx: ChannelHandlerContext?, msg: ByteBuf?, out: MutableList<Any>?)
 * 首先从数据报msg(数据类型取决于继承MessageToMessageDecoder时填写的泛型类型)中获取需要解码的byte数组
 * 然后调用MessagePack的read方法将其反序列化(解码)为Object对象
 * 将解码后的对象加入到解码列表out中,这样就完成了MessagePack的解码操作
 */
class DecodeHandler : MessageToMessageDecoder<ByteBuf?>() {
    override fun decode(ctx: ChannelHandlerContext?, msg: ByteBuf?, out: MutableList<Any>?) {
        //TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        // 从数据报msg中(这里的数据类型为ByteBuf,因为Netty的通信基于ByteBuf对象)
//        val length:Int =msg!!.readableBytes();
//        val array: ByteArray = ByteArray(length);
     // var  bytes= ByteString.decodeHex(msg!!.readableBytes().toString()).toByteArray();
        /**
         * 这里使用的是ByteBuf的getBytes方法来将ByteBuf对象转换为字节数组,前面是使用readBytes,直接传入一个接收的字节数组参数即可
         * 这里的参数比较多,第一个参数是index,关于readerIndex,说明如下:
         * ByteBuf是通过readerIndex跟writerIndex两个位置指针来协助缓冲区的读写操作的,具体原理等到Netty源码分析时再详细学习一下
         * 第二个参数是接收的字节数组
         * 第三个参数是dstIndex the first index of the destination
         * 第四个参数是length   the number of bytes to transfer
         */
   // msg.getBytes(msg.readerIndex(), array, 0, length)

/*========Convert binary MessagePack back to an Object MessagePack转换为对象时================*/
//        val bytes = ByteString.decodeHex("82a7636f6d70616374c3a6736368656d6100").toByteArray()
//        val moshiPack = MoshiPack()
//        val plug: MessagePackWebsitePlug = moshiPack.unpack(bytes)
/*=====================================================================================*/

//        out!!.add( MoshiPack().unpack(byte))
        // 创建一个MessagePack对象  使用;json 字符串的解析
//        val listCars: List<Any> = MoshiPack.unpack(bytes)
//        //var objects :Any = MoshiPack().unpack(bytes);
//        // 解码并添加到解码列表out中
//        out!!.add(listCars)

        /*jsonToMsgpack
直接从JSON转换为MessagePack字节。由于在该过程中没有实例化对象,因此使用此方法进行最有效的实现。返回 BufferedSource
实例版本:(需要String或BufferedSource)*/
        var msgToStr:String =msg!!.readableBytes().toString();
        LogUtils.d("EncodeHandler", "msgToStr=" + msgToStr)
        var bufferedSource: BufferedSource =   MoshiPack().jsonToMsgpack(msgToStr)
        var objects: Any =   MoshiPack().jsonToMsgpack(bufferedSource)
        out!!.add(objects)
        LogUtils.d("EncodeHandler", "objects=" + objects.toString())
    }

}


//     //   MessageToMessageDecoder
//        LengthFieldBasedFrameDecoder {
////    private val MAX_FRAME_LENGTH = 1024 * 1024
////    private val LENGTH_FIELD_LENGTH = 4
////    private val LENGTH_FIELD_OFFSET = 1
////    private val LENGTH_ADJUSTMENT = 0
////    private val INITIAL_BYTES_TO_STRIP = 0
//
//    constructor(maxFrameLength: Int=1024 * 1024, lengthFieldOffset: Int= 4,
//                lengthFieldLength: Int= 1, lengthAdjustment: Int= 0,
//                initialBytesToStrip: Int= 0, failFast: Boolean=true):super(maxFrameLength, lengthFieldOffset,
//            lengthFieldLength, lengthAdjustment,
//            initialBytesToStrip, failFast);
//
//
//    override fun decode(ctx: ChannelHandlerContext?, `in`: ByteBuf?): Any? {
//        LogUtils.d("DecodeHandler","接收到数据返回信息。。。");
//        if (`in` == null||`in`.readableBytes() < 5) {
//           // `in`.resetReaderIndex()
//            return super.decode(ctx, `in`)
//        }
//        var moshiPack : MoshiPack = MoshiPack();
//        val packed: BufferedSource = moshiPack.pack(`in`);
//
//        /**
//         * 通过源码我们能看到在读的过程中
//         * 每读一次读过的字节即被抛弃
//         * 即指针会往前跳
//         */
//
//        if (`in`.readableBytes() < packed!!.readInt()) {
//            //`in`.resetReaderIndex();
//            return super.decode(ctx, `in`)
//        }
//        val buf = `in`.readBytes(packed!!.readInt())
//        val b = ByteArray(buf.readableBytes())
//        buf.readBytes(b)
//        return packed;
//    }
//
//}

接收到的数据处理

package com.ftrd.flashlight.nettys.handlers

import com.daveanthonythomas.moshipack.MoshiPack
import com.ftrd.flashlight.FileKt.FinalValue.MSG_HEAD
import com.ftrd.flashlight.FileKt.LogUtils
import com.ftrd.flashlight.FlashLight.Companion.eBus
import com.ftrd.flashlight.nettys.NettyConnect.nettyConnect
import com.ftrd.flashlight.nettys.NettyConnect.nettyDestroy
import com.ftrd.flashlight.nettys.builds.RegistertBuild
import com.ftrd.flashlight.nettys.buss.LoginBus
import io.netty.channel.ChannelHandlerAdapter
import io.netty.channel.ChannelHandlerContext
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.TimeUnit


/**
 * @author: Jeff <[email protected]>
 * @date:  2018-05-16 16:56
 * @description: 接收到的数据处理
 *
 * ChannelDuplexHandler 则同时实现了 ChannelInboundHandler 和 ChannelOutboundHandler 接口。
 * 如果一个所需的ChannelHandler既要处理入站事件又要处理出站事件,推荐继承此类。
 *
 * 当然这里使用的是netty4
 * 如果使用netty5使用 ChannelHandlerAdapter 也同样实现 ChannelInboundHandler 和 ChannelOutboundHandler 接口
 */
class MsgHandler : ChannelHandlerAdapter() {

    override fun channelActive(ctx: ChannelHandlerContext?) {
        super.channelActive(ctx)
//        if (ctx!!.channel()!!.isActive) {
//            ctx!!.close()
//
//        } else {
        //注册设备,服务器连接成功,注册通道,认证
        LogUtils.d("MsgHandler", "channelActive")
        //在这里只做发送注册的信息
        ctx!!.writeAndFlush(RegistertBuild());
        //在这里发送心跳
//        //0029,000004,,C3,170413 181858,10#心跳包设置
//        //  val time = Integer.parseInt(arr[5].replace("#", ""))
        ctx?.executor()?.scheduleAtFixedRate(
                {
                    ctx.writeAndFlush(MSG_HEAD);
                    LogUtils.d("MsgHandler", "channelActive里发送心跳${MSG_HEAD}---${TimeUnit.SECONDS}")
                },
                0,
                30,
                TimeUnit.SECONDS)

        //   }
    }

    override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
        super.exceptionCaught(ctx, cause);
        LogUtils.d("MsgHandler", cause?.message.toString());
        if (ctx!!.channel().isOpen() && ctx!!.channel()!!.isActive) {
            nettyDestroy();//关闭服务器连接
            //ctx!!.close();
              nettyConnect();//连接服务器
        }

    }

    override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
        LogUtils.d("MsgHandler", "channelRead=${msg!!.toString()}");
        // val value:String = String(msg as ByteArray);
        val listCars: List<Any> = (msg!! as List<Any>)
        LogUtils.d("MsgHandler", "channelRead=${listCars!!.toString()}");
            when (listCars.get(0) ) {
                "C0" -> {
                    // C0:[0048,000004,,C0,170413 181858,V1,170413 181618,0,1]设备注册成功返回值

                }
                "C120" -> {
                    //C120:[0054,000003,,C120,170414 110212,V120,170414 110212,1,0,ok] 登录返回值

                }
//            "C3"->{
//                //[0029,000004,,C3,170413 181858,10]心跳包设置
//                //  val time = Integer.parseInt(arr[5].replace("#", ""))
//                ctx?.executor()?.scheduleAtFixedRate(
//                        {
//                            ctx.writeAndFlush(MSG_HEAD)
//                            LogUtils.d("MsgHandler", "channelActive里发送心跳${MSG_HEAD}---${TimeUnit.SECONDS}")
//                        },
//                        0,
//                        10,
//                        TimeUnit.SECONDS)
//            }



        }
        super.channelRead(ctx, msg)
    }


}

Kotlin Netty连接器可以点击这里

猜你喜欢

转载自blog.csdn.net/Jeff_YaoJie/article/details/80341135