我们可以自定义发送消息和接受消息的协议,设计一段协议往往包含这几个部分。
1.魔法值
这个魔法值往往放在一段消息的前面,这个值可以自己去定义,主要的作用是确认这个消息是根据自己的协议设计的,如果这段消息的协议都不是自己设计,那么后面根据自己的协议去解析消息将毫无意义。
2.版本号
这个从名字就知道这个是规定我们消息的版本号,因为这个协议我们后面看你会有版本更替,我们我们要确定这个是那个版本的,用那个版本的协议去解析。
3.消息的序列化类型
我们的的消息在网络的传输中,必须要采用序列化传输,这里就要指定是那中序列化类型,后面我们好去解析。
4.消息的类型
我们的消息有多种的类型,这里就是确定到底是哪种消息。
5.消息的序号
我们在发送消息和接受的消息的时候是异步的,所有我们要标注消息的序号。
6.消息的长度
我们要把我们要发送消息的正文的长度也写进去。
7.消息的正文
这里就是把我们真的消息的内容写进去。
下面是一个小的案列
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import message.Message;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
@Slf4j
@ChannelHandler.Sharable
public class MessageCodec extends ByteToMessageCodec<Message> {
@Override
public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
// 1. 4 字节的魔数
out.writeBytes(new byte[]{1, 2, 3, 4});
// 2. 1 字节的版本,
out.writeByte(1);
// 3. 1 字节的序列化方式 jdk 0 , json 1
out.writeByte(0);
// 4. 1 字节的指令类型
out.writeByte(msg.getMessageType());
// 5. 4 个字节
out.writeInt(msg.getSequenceId());
// 无意义,对齐填充
out.writeByte(0xff);
// 6. 获取内容的字节数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(msg);
byte[] bytes = bos.toByteArray();
// 7. 长度
out.writeInt(bytes.length);
// 8. 写入内容
out.writeBytes(bytes);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int magicNum = in.readInt();
byte version = in.readByte();
byte serializerType = in.readByte();
byte messageType = in.readByte();
int sequenceId = in.readInt();
in.readByte();
int length = in.readInt();
byte[] bytes = new byte[length];
in.readBytes(bytes, 0, length);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
Message message = (Message) ois.readObject();
log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
log.debug("{}", message);
out.add(message);
}
}
上面的代码就是根据上面的规则进行对消息进行下、设置,后面就是根据协议来解析里面的内容。