我正在尝试为小型服务器编写数据包侦听器。我对 Java 很陌生,这是我第一次搞乱网络。整个想法是接收数据包,将数据包ID与其类匹配,将输入流传递给数据包的构造函数,以便可以构造它,然后将其提供给packetHander,每个数据包都有一个重叠的方法。为了实现这一点,我使用了一个数组,该数组将数据包 id 映射到每个类的类,并使用一种称为 decode 的方法来构造数据包。问题是handlePacket 的重载,它的行为不符合预期。让我们看一些代码。
我在线程中运行了数据包侦听器,运行方法如下所示:
public void run() {
try {
int packet_id;
while ((packet_id = istream.readInt()) != -1) {
plugin.getServer().getConsoleSender().sendMessage("[Comm] Recived packet " + packet_id);
Packet packet = decode(packet_id, istream);
plugin.getServer().getConsoleSender().sendMessage("[Comm] Packet is " + Class.forName(packet.getClass().getName()));
plugin.getServer().getConsoleSender().sendMessage("[Comm] Class is " + Packet00ReqIdentify.class.cast(packet).getClass().getName());
plugin.getServer().getConsoleSender().sendMessage("[Comm] Class is " + Class.forName(packet.getClass().getName()).getName());
handlePacket(packet);
}
} catch (IOException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException e) {
e.printStackTrace();
}
}
decode 和 handlePacket 方法如下所示:
private void handlePacket(Packet00ReqIdentify packet) throws IOException {
plugin.getServer().getConsoleSender().sendMessage("[Comm] Got it!");
}
private void handlePacket(Packet packet) {
plugin.getServer().getConsoleSender().sendMessage("[Comm] Woops!");
}
private Packet decode(int packet_id, PacketInputStream istream) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException {
Class<? extends Packet> packet_class = packets_ids.get(packet_id);
try {
Constructor<?> packet_constructor = packet_class.getConstructor(PacketInputStream.class);
return Class.forName(packet_class.getName()).asSubclass(Packet.class).cast(packet_constructor.newInstance(istream));
} catch (NoSuchMethodException e) {
return Class.forName(packet_class.getName()).asSubclass(Packet.class).cast(packet_class.newInstance());
}
}
packet_ids 它是一个数组,其中包含对每个数据包类的引用,由它们的 id 索引:
private static ArrayList<Class<? extends Packet>> packets_ids;
它以这种方式初始化:
private static void registerPacket(int id, Class<? extends Packet> oclass) {
packets_ids.add(id, oclass);
}
static {
packets_ids = new ArrayList<Class<? extends Packet>>();
registerPacket(Packet00ReqIdentify.assigned_pid, Packet00ReqIdentify.class);
registerPacket(Packet01Identify.assigned_pid, Packet01Identify.class);
registerPacket(Packet02Heartbeat.assigned_pid, Packet02Heartbeat.class);
}
如果我执行这个并测试它发送一个类型为 00 的数据包,我得到这个:
17:37:49 [INFO] [Comm] Connection established to localhost:11000
17:37:49 [INFO] [Comm] Recived packet 0
17:37:49 [INFO] [Comm] Packet is class com.gamerarg.commclient.protocol.Packet00ReqIdentify
17:37:49 [INFO] [Comm] Class is com.gamerarg.commclient.protocol.Packet00ReqIdentify
17:37:49 [INFO] [Comm] Class is com.gamerarg.commclient.protocol.Packet00ReqIdentify
17:37:49 [INFO] [Comm] Woops!
所以这意味着 packet00 没有被“handlePacket(Packet00ReqIdentify packet)”处理。如果我在 handlePacket 调用中对“数据包”进行显式转换,它就可以工作。所以问题是:
为什么这不起作用?当我为两者打印类名时,我得到了相同的结果。
我怎样才能让它工作?我已经为此苦苦挣扎了 6 或 7 个小时,阅读、搜索、尝试和查看其他人的代码。一个更简单的解决方案是使用数据包 ID 进行切换,但我想要更优雅的东西。也许我的基本想法是错误的,所以这就是我发布代码的原因,我愿意接受该主题中更有经验的人的建议和想法,包括对该主题材料的推荐。
谢谢!