diff --git a/pom.xml b/pom.xml index 8d394d4..7d31938 100644 --- a/pom.xml +++ b/pom.xml @@ -10,6 +10,9 @@ 4.1.6.Final + 1.16.12 + 1.2.29 + 4.12 @@ -18,6 +21,25 @@ netty-all ${netty-all.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + com.alibaba + fastjson + ${fastjson.version} + + + + junit + junit + ${junit.version} + + diff --git a/src/main/java/the/flash/protocol/command/Command.java b/src/main/java/the/flash/protocol/command/Command.java new file mode 100644 index 0000000..31b3d26 --- /dev/null +++ b/src/main/java/the/flash/protocol/command/Command.java @@ -0,0 +1,6 @@ +package the.flash.protocol.command; + +public interface Command { + + Byte LOGIN_REQUEST = 1; +} diff --git a/src/main/java/the/flash/protocol/command/LoginRequestPacket.java b/src/main/java/the/flash/protocol/command/LoginRequestPacket.java new file mode 100644 index 0000000..d24753b --- /dev/null +++ b/src/main/java/the/flash/protocol/command/LoginRequestPacket.java @@ -0,0 +1,19 @@ +package the.flash.protocol.command; + +import lombok.Data; + +import static the.flash.protocol.command.Command.LOGIN_REQUEST; + +@Data +public class LoginRequestPacket extends Packet { + private Integer userId; + + private String username; + + private String password; + + @Override + public Byte getCommand() { + return LOGIN_REQUEST; + } +} diff --git a/src/main/java/the/flash/protocol/command/Packet.java b/src/main/java/the/flash/protocol/command/Packet.java new file mode 100644 index 0000000..c4a5945 --- /dev/null +++ b/src/main/java/the/flash/protocol/command/Packet.java @@ -0,0 +1,17 @@ +package the.flash.protocol.command; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +@Data +public abstract class Packet { + /** + * 协议版本 + */ + @JSONField(deserialize = false, serialize = false) + private Byte version = 1; + + + @JSONField(serialize = false) + public abstract Byte getCommand(); +} diff --git a/src/main/java/the/flash/protocol/command/PacketCodeC.java b/src/main/java/the/flash/protocol/command/PacketCodeC.java new file mode 100644 index 0000000..d70f787 --- /dev/null +++ b/src/main/java/the/flash/protocol/command/PacketCodeC.java @@ -0,0 +1,85 @@ +package the.flash.protocol.command; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import the.flash.serialize.Serializer; +import the.flash.serialize.impl.JSONSerializer; + +import java.util.HashMap; +import java.util.Map; + +import static the.flash.protocol.command.Command.LOGIN_REQUEST; + +public class PacketCodeC { + + private static final int MAGIC_NUMBER = 0x1234; + private static final Map> packetTypeMap; + private static final Map serializerMap; + + static { + packetTypeMap = new HashMap<>(); + packetTypeMap.put(LOGIN_REQUEST, LoginRequestPacket.class); + + serializerMap = new HashMap<>(); + Serializer serializer = new JSONSerializer(); + serializerMap.put(serializer.getSerializerAlogrithm(), serializer); + } + + + public ByteBuf encode(Packet packet) { + // 1. 创建 ByteBuf 对象 + ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer(); + // 2. 序列化 java 对象 + byte[] bytes = Serializer.DEFAULT.serialize(packet); + + // 3. 实际编码过程 + byteBuf.writeInt(MAGIC_NUMBER); + byteBuf.writeByte(packet.getVersion()); + byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlogrithm()); + byteBuf.writeByte(packet.getCommand()); + byteBuf.writeInt(bytes.length); + byteBuf.writeBytes(bytes); + + return byteBuf; + } + + + public Packet decode(ByteBuf byteBuf) { + // 跳过 magic number + byteBuf.skipBytes(4); + + // 跳过版本号 + byteBuf.skipBytes(1); + + // 序列化算法 + byte serializeAlgorithm = byteBuf.readByte(); + + // 指令 + byte command = byteBuf.readByte(); + + // 数据包长度 + int length = byteBuf.readInt(); + + byte[] bytes = new byte[length]; + byteBuf.readBytes(bytes); + + Class requestType = getRequestType(command); + Serializer serializer = getSerializer(serializeAlgorithm); + + if (requestType != null && serializer != null) { + return serializer.deserialize(requestType, bytes); + } + + return null; + } + + private Serializer getSerializer(byte serializeAlgorithm) { + + return serializerMap.get(serializeAlgorithm); + } + + private Class getRequestType(byte command) { + + return packetTypeMap.get(command); + } +} diff --git a/src/main/java/the/flash/serialize/Serializer.java b/src/main/java/the/flash/serialize/Serializer.java new file mode 100644 index 0000000..6abe22b --- /dev/null +++ b/src/main/java/the/flash/serialize/Serializer.java @@ -0,0 +1,25 @@ +package the.flash.serialize; + +import the.flash.serialize.impl.JSONSerializer; + +public interface Serializer { + + Serializer DEFAULT = new JSONSerializer(); + + /** + * 序列化算法 + * @return + */ + byte getSerializerAlogrithm(); + + /** + * java 对象转换成二进制 + */ + byte[] serialize(Object object); + + /** + * 二进制转换成 java 对象 + */ + T deserialize(Class clazz, byte[] bytes); + +} diff --git a/src/main/java/the/flash/serialize/SerializerAlogrithm.java b/src/main/java/the/flash/serialize/SerializerAlogrithm.java new file mode 100644 index 0000000..0108ead --- /dev/null +++ b/src/main/java/the/flash/serialize/SerializerAlogrithm.java @@ -0,0 +1,8 @@ +package the.flash.serialize; + +public interface SerializerAlogrithm { + /** + * json 序列化 + */ + byte JSON = 1; +} diff --git a/src/main/java/the/flash/serialize/impl/JSONSerializer.java b/src/main/java/the/flash/serialize/impl/JSONSerializer.java new file mode 100644 index 0000000..251f141 --- /dev/null +++ b/src/main/java/the/flash/serialize/impl/JSONSerializer.java @@ -0,0 +1,25 @@ +package the.flash.serialize.impl; + +import com.alibaba.fastjson.JSON; +import the.flash.serialize.Serializer; +import the.flash.serialize.SerializerAlogrithm; + +public class JSONSerializer implements Serializer { + + @Override + public byte getSerializerAlogrithm() { + return SerializerAlogrithm.JSON; + } + + @Override + public byte[] serialize(Object object) { + + return JSON.toJSONBytes(object); + } + + @Override + public T deserialize(Class clazz, byte[] bytes) { + + return JSON.parseObject(bytes, clazz); + } +} diff --git a/src/test/java/the/flash/protocol/command/PacketCodeCTest.java b/src/test/java/the/flash/protocol/command/PacketCodeCTest.java new file mode 100644 index 0000000..8e51cbd --- /dev/null +++ b/src/test/java/the/flash/protocol/command/PacketCodeCTest.java @@ -0,0 +1,28 @@ +package the.flash.protocol.command; + +import io.netty.buffer.ByteBuf; +import org.junit.Assert; +import org.junit.Test; +import the.flash.serialize.Serializer; +import the.flash.serialize.impl.JSONSerializer; + +public class PacketCodeCTest { + @Test + public void encode() { + + Serializer serializer = new JSONSerializer(); + LoginRequestPacket loginRequestPacket = new LoginRequestPacket(); + + loginRequestPacket.setVersion(((byte) 1)); + loginRequestPacket.setUserId(123); + loginRequestPacket.setUsername("zhangsan"); + loginRequestPacket.setPassword("password"); + + PacketCodeC packetCodeC = new PacketCodeC(); + ByteBuf byteBuf = packetCodeC.encode(loginRequestPacket); + Packet decodedPacket = packetCodeC.decode(byteBuf); + + Assert.assertArrayEquals(serializer.serialize(loginRequestPacket), serializer.serialize(decodedPacket)); + + } +}