网络通信从编解码开始,前面的第一篇文章中,介绍过数据包的结构,这篇文章就要介绍一下拆包和组包的过程。
1. 包头字段的设计目的
A. 起始分隔符:标明一个数据包的开始部分(里面还隐含了小端模式的信息,这个小端模式可以忽略);
B. 协议的版本:当前版本是明文传输的,考虑到后期升级可能要采用密文传输包体,所以,设计了一个版本字段,当然,也可以用于协议内容的扩充,添加新的数据包类型时增加版本号的即可;
C. 频道号:这个字段的作用不明显,目前是想将包信息按照业务分类,比如:网络连接,权限认证,聊天信息等;
D. 命令字:与频道号、版本号联合起来作为包体类型的ID,参与Json串和Java对象的转换操作;
2. 包体
要传输的Json字符串,二进制的形式,采用UTF-8的编码形式;
3. 包尾
结束分隔符:标明一个数据包的结束部分,如果按照包长度解析错误之后,可以通过结束分隔符丢弃碎包,目前Demo没有完成这个功能。
package houlei.net.tcp.codec;
import houlei.net.tcp.pkg.PackageVersion;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
public class GenericPackageCodec extends ByteToMessageCodec<GenericPackage> {
public static final int HEADER_TAIL_LENGTH = 16;
public static final int PKG_MAX_LENGTH = 2048;
// 编码过程
@Override
protected void encode(ChannelHandlerContext ctx, GenericPackage pkg, ByteBuf out) throws Exception {
switch (PackageVersion.valueOf(pkg.getVersion())) {
case V10:
encodeV10(ctx, pkg, out);
return;
default:
encodeVX(ctx, pkg, out);
return;
}
}