我想在Java中实现现有协议(仅限服务器端)。客户端是一个旧游戏客户端,我想为其编写服务器。
协议的结构如下:
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+----//----+--------+--------+
| size0 | size1 | seq0 | seq1 | sessID0| sessID1| param0 | param1 | id0 | id1 | payload | trash | trash |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+----//----+--------+--------+
现在这个协议很老了,它定义了许多版本,其中标题(直到包含id1
)保持不变(与最后两个填充字节一样)。
payload
因版本而异,因此需要对其进行不同的解码。请参阅下面的简化示例(pl#
了解有效负载字节数):
Version 1.00
...+--------+--------+--------+--------+--------+--------/--------+--------+...
(HEAD) | pl0 | pl1 | pl2 | pl3 | pl4 | pl5 ... pl22 | pl23 |
...+--------+--------+--------+--------+--------+--------/--------+--------+...
| clientVersion (little endian) | userName (fixed String l=20) |
...+--------+--------+--------+--------+--------+--------/--------+--------+
Version 1.10
...+--------+--------+--------+--------+--------+--------/--------+--------+...
(HEAD) | pl0 | pl1 | pl2 | pl3 | pl4 | pl5 ... plN-1 | plN |
...+--------+--------+--------+--------+--------+--------/--------+--------+...
| clientVersion (big endian) | userName (pascal String) |
...+--------+--------+--------+--------+--------+--------/--------+--------+
现在我的问题是双重的。
首先,如何在不进入switch()
地狱的情况下实施这样的协议?我已经读过很多人推荐FSM(或者可能是状态模式),但我没有得到它应该如何工作。我一直在研究(和玩)Google的ProtoBuf,遗憾的是它不支持任何int16 / uint16数据类型。
其次,如何实现这一点,以便最终得到一个漂亮,干净的PacketHandler
接口,可能如下所示:
public interface PacketHandler {
void onLoginRequest(Client client, LoginRequest request);
void onHeartbeatRequest(Client client, HeartbeatRequest request);
...
}
该处理程序的目的是,无论客户端版本如何,类LoginRequest
和HeartbeatRequest
都是相同的。
在我希望能够编写这些POJO的事情的外向方面,例如:
public class PacketHandlerImpl implements PacketHandler {
void onLoginRequest(Client client, LoginRequest request) {
if(success)
client.send(new LoginGrantedResponse(...));
else
client.send(new LoginDeniedResponse(...));
}
...
}
提前感谢您的帮助!