繁体   English   中英

Java 套接字连接:从输入 Stream 接收完全任意整数

[英]Java Socket Connection: receiving completely arbitrary integers from the Input Stream

我一直在学习 Java 中的 sockets,以便在我一直在研究的迷你游戏程序的两个单独的 Java 应用程序之间发送信息。 目标是能够拥有它,以便服务器 A 可以通过在 switch 语句中写入和读取整数来告诉服务器 B 做某事。 这是我为服务器端套接字提供的代码:

@Override
public void run() {
    try (
            DataInputStream input = new DataInputStream(this.socket.getInputStream())
    ) {
        this.output = new DataOutputStream(this.socket.getOutputStream());
        while (!this.finished) {
            int type = input.readInt();
            this.plugin.getLogger().info("Type: " + type + " from " + this.socket.getRemoteSocketAddress());
            switch (type) {
                case 1: {
                    ServerManager.getInstance().addActiveServer(this.serverInfo, input.readInt());
                    break;
                }
                case 2: {
                    int length = input.readInt();
                    for (int i = 0; i < length; i++) {
                        UUID uuid = UUID.fromString(input.readUTF());
                        PlayerData playerData = PlayerManager.getInstance().getPlayerData(uuid);
                        if (playerData == null) {
                            continue;
                        }
                        playerData.setPlaying(false);
                        playerData.setSpectating(false);
                        playerData.setQueuing(false);
                        playerData.getPlayer().connect(this.plugin.getLobbyServer());
                    }
                    ServerManager.getInstance().addInactiveServer(this.serverInfo);
                    break;
                }
                case 3: {
                    int length = input.readInt();
                    for (int i = 0; i < length; i++) {
                        UUID uniqueId = UUID.fromString(input.readUTF());
                        PlayerData playerData = PlayerManager.getInstance().getPlayerData(uniqueId);
                        if (playerData == null) {
                            continue;
                        }
                        playerData.setQueuing(true);
                    }
                    break;
                }
                default:
            }
        }

        this.output.close();
        this.socket.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

当 Minigame 开始倒计时序列时,它会在 Minigame 实际启动时写入并刷新“3”之前将“1”写入服务器端套接字。

// Tells Server A that the max players have been met
// and to start a countdown sequence for a Minigame.
public void sendStartUpdate(int gameKey) {
    try {
        this.output.writeInt(1);
        this.output.writeInt(gameKey);
        this.output.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Lets Server A know that the player is queued up for a Minigame
public void sendQueuingUpdate(@NotNull Collection<UUID> players) throws IOException {
    this.output.writeInt(3);
    this.output.writeInt(players.size());
    for (UUID player : players) {
        this.output.writeUTF(String.valueOf(player));
    }
    this.output.flush();
}

但是,出于某种原因,每当我运行程序时,服务器首先会按预期接收到“1”和“3”,然后会突然从服务器 B 接收到一系列非常长的整数。

[02:45:24 INFO] Type: 1                     // This is good!
[02:45:27 INFO] Type: 3                     // This is good!
[02:45:43 INFO] Type: 16777216              // Huh??
[02:45:43 INFO] Type: 1280                  // WHAT???
[02:45:43 INFO] Type: 256                   // Insert confused guy meme here
[02:45:43 INFO] Type: 610548020
[02:45:43 INFO] Type: 1667643705
[02:45:43 INFO] Type: 925721650
[02:45:43 INFO] Type: 842018100
[02:45:43 INFO] Type: 878785581
[02:45:43 INFO] Type: 1647785059
[02:45:43 INFO] Type: 761477426
[02:45:43 INFO] Type: 825570148
[02:45:43 INFO] Type: 1647851062

当小游戏结束并且程序通知服务器 A 小游戏已经结束时,也会发生此问题。 直到我对下面的代码做了一点修改,我才遇到这个问题:

public void sendPlayingUpdate(@NotNull Collection<UUID> players) throws IOException {
    this.output.writeBoolean(true);
    this.output.writeBoolean(false);
    this.output.writeBoolean(false);
    this.output.writeInt(5);
    this.output.writeInt(players.size());
    for (UUID player : players) {
        this.output.writeUTF(String.valueOf(player));
    }
//  this.output.writeInt(4);
//  this.output.writeInt(players.size());
//  for (UUID uuid : players) {
//      this.output.writeUTF(String.valueOf(uuid));
//  }
    this.output.flush();
}

注释掉的位是原始代码。 如果我用未注释的代码替换它,它会给出所有那些任意大的整数。 有没有办法让另一个应用程序以某种方式连接到与套接字相同的端口并开始提供随机信息? 我只是不明白一个小的微小变化如何导致发送 1667643705 之类的东西,整数老实说让我想起了哈希码。

我很感激任何事情。

时间戳表示第二个和第三个数据包之间有 16 秒的间隔。 所以它可能不是第二个3数据包损坏。 在其他地方,您在未提供代码中发送格式错误的数据包。

数据是:

01 00 00 00  00 00 05 00  00 00 01 00  24 [... load of hex ...]

0x24$ ,但可能是来自writeUTF的字符串长度 - 例如,两个 UUID 连接。

我将开始测试解析代码可以解释格式代码的 output 而不需要所有服务器的东西。 作为一个好处,这将需要更好地分解代码。

从您的服务器端代码来看,您的协议似乎如下工作

  • 数据包 ID (int):4 字节
  • N 字节的数据包特定内容

您的服务器端代码识别 3 种不同类型的数据包,并忽略所有未识别的数据包,但 output 他们的数据包 ID。

最可能的情况是您的一个数据包没有被完全解析,因此您有剩余的数据,它试图将其解析为一个新数据包。 我知道这不是一个完整的答案,但没有你的完整程序,我无法调试。

我建议为您的数据包处理逻辑创建一个单元测试,在其中创建一个仅包含单个数据包的 DataInputStream。 对于每个数据包,您检查它是否被正确处理,以及处理后是否有任何剩余数据。 这应该使您能够发现问题。

在我看来,兄弟您可能在同一端口上运行了其他东西 - 使用 netstat -ano 检查 CMD,也可以在任务管理器中查看当前连接。 您可能有多个实例在同一个端口或使用所选端口号的其他应用程序上发送或侦听 - 让我们尝试更改端口号,如果有变化,请告诉我们。 还有一个:如果有人使用 readUTF,对方必须使用 writeUTF !!!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM