1.注意ChannelPipeline中handler的调用顺序。完整的发送与接收过程,是先发送再接收,所以是先执行out再执行in。具体参考https://blog.csdn.net/u014614038/article/details/80487942
2.发送数据转码,通过MessageToByteEncoder,比如我使用的是SMessage格式数据:
public class SDataEncoder extends MessageToByteEncoder<SMessage> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, SMessage sMessage, ByteBuf byteBuf) throws Exception {
if (sMessage != null) {
ByteBuf encoded = channelHandlerContext.alloc().buffer(sMessage.getByteData().length);
encoded.writeBytes(sMessage.getByteData());
channelHandlerContext.writeAndFlush(encoded);
channelHandlerContext.flush();
}
}
}
3.接收数据转码,通过ByteToMessageDecoder,比如将字节数据转为我使用的SMessage:
public class SDataDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
try {
ByteBuf d = in.readBytes(in.readableBytes());
byte[] bs = new byte[d.readableBytes()];
d.readBytes(bs);
if (bs.length>0) {
SMessage sMessage = new SMessage();
sMessage.data = bs;
//获取header
if (sMessage.hasData() && sMessage.data.length >= SHeader.LENGTH) {
byte[] headBs = new byte[SHeader.LENGTH];
System.arraycopy(sMessage.data, 0, headBs, 0, headBs.length);
sMessage.header = new SHeader();
sMessage.header.setData(headBs);
}
//获取数据body
if (sMessage.hasData() && sMessage.data.length > SHeader.LENGTH) {
byte[] bodyBs = new byte[sMessage.data.length - SHeader.LENGTH];
System.arraycopy(sMessage.data, SHeader.LENGTH, bodyBs, 0, bodyBs.length);
sMessage.body = new SBody();
sMessage.body.dataByte = bodyBs;
}
out.add(sMessage);
} else {
out.add(d);
}
} catch (Exception e) {
System.out.println("SDataDecoder decode Exception:" + e.toString());
}
}
}
这里记得注意的是,不能直接使用ByteBuf,否则会报Exception:java.lang.UnsupportedOperationException: direct buffer异常,需要通过 in.readBytes(in.readableBytes())复制一个新的ByteBuf然后读取字节数据。
4.发送过程抛出异常,包括自己代码写的不好导致的,最终会回调到ClientDataHandler的channelInactive,如果在这个方法执行了重连,可能会导致不断重连,建议捕捉下,避免代码导致的不断重连(比如心跳发送抛出异常,而你会不断发送心跳包)。
5.ChannelHandler都是异步线程中的中执行的,所以任何回调到主线程使用的方法,最终都应该通过主线程回调,否则会不断自动进行断开重连,比如ClientDataHandler中channelActive监听这个方法然后使用我们的监听器stateListener.onActive()回调,这个stateListener.onActive()应该在主线程执行可以(通过mainHandler)。
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
if (stateListener != null) {
mainHandler.post(new Runnable() {
@Override
public void run() {
stateListener.onActive();
}
});
}
}
转载注明:https://blog.csdn.net/u014614038/article/details/80497785