仍然需要注意的是,我使用的是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?)
* 它负责将Object类型的POJO对象编码为byte数组,然后写入到ByteBuf中
*
*/
internal class EncodeHandler : MessageToMessageEncoder() {
override fun encode(ctx: ChannelHandlerContext?, msg: Any?, out: MutableList?) {
// 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?)
* 首先从数据报msg(数据类型取决于继承MessageToMessageDecoder时填写的泛型类型)中获取需要解码的byte数组
* 然后调用MessagePack的read方法将其反序列化(解码)为Object对象
* 将解码后的对象加入到解码列表out中,这样就完成了MessagePack的解码操作
*/
class DecodeHandler : MessageToMessageDecoder() {
override fun decode(ctx: ChannelHandlerContext?, msg: ByteBuf?, out: MutableList?) {
//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 = 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 = (msg!! as List)
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连接器可以点击这里