简体   繁体   English

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

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

I've been learning about sockets in Java to send information between two separate Java applications for a Minigame program I've been working on.我一直在学习 Java 中的 sockets,以便在我一直在研究的迷你游戏程序的两个单独的 Java 应用程序之间发送信息。 The goal is to be able to have it so that Server A can tell Server B to do something by writing and reading ints in a switch statement.目标是能够拥有它,以便服务器 A 可以通过在 switch 语句中写入和读取整数来告诉服务器 B 做某事。 This is the code I have for the server-side socket:这是我为服务器端套接字提供的代码:

@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();
    }
}

When the Minigame begins the countdown sequence, it writes and flushes '1' to the server-side socket before writing and flushing '3' when the Minigame actually starts.当 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();
}

However, for some reason, whenever I run the program, the server first receives '1' and '3' as expected, but then receives a series of really long integers from Server B out of nowhere.但是,出于某种原因,每当我运行程序时,服务器首先会按预期接收到“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

This issue also happens when the Minigame ends and the program notifies Server A that the Minigame has ended.当小游戏结束并且程序通知服务器 A 小游戏已经结束时,也会发生此问题。 I didn't have this problem until I made a slight modification to the code below:直到我对下面的代码做了一点修改,我才遇到这个问题:

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();
}

The commented-out bit is the original code.注释掉的位是原始代码。 If I replace it with the uncommented code, it gives all those arbitrarily large integers.如果我用未注释的代码替换它,它会给出所有那些任意大的整数。 Is there a way for another application to somehow connect to the same port as the socket and begin feeding random information?有没有办法让另一个应用程序以某种方式连接到与套接字相同的端口并开始提供随机信息? I just don't see how one small minor change can lead to something like 1667643705 being sent, the integers honestly remind me of hashcodes.我只是不明白一个小的微小变化如何导致发送 1667643705 之类的东西,整数老实说让我想起了哈希码。

I appreciate anything.我很感激任何事情。

The timestamps indicate a 16 second gap between the second and third packet.时间戳表示第二个和第三个数据包之间有 16 秒的间隔。 So it's likely not the second 3 packet that is corrupt.所以它可能不是第二个3数据包损坏。 Somewhere else you are sending a malformed packet in code not presented.在其他地方,您在未提供代码中发送格式错误的数据包。

The data is:数据是:

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

0x24 is $ , but could be a string length from a writeUTF - say, the two UUIDs concatenated. 0x24$ ,但可能是来自writeUTF的字符串长度 - 例如,两个 UUID 连接。

I would start off testing the parse code can interpret the output of the format code without all the server stuff.我将开始测试解析代码可以解释格式代码的 output 而不需要所有服务器的东西。 As a benefit, that will require factoring the code better.作为一个好处,这将需要更好地分解代码。

Judging by your server-side code it seems that your protocol works as follows从您的服务器端代码来看,您的协议似乎如下工作

  • Packet ID (int): 4 bytes数据包 ID (int):4 字节
  • N bytes of packet-specific content N 字节的数据包特定内容

Your server-side code recognizes 3 different types of packets, and ignores all non-identified packets but does output their Packet ID.您的服务器端代码识别 3 种不同类型的数据包,并忽略所有未识别的数据包,但 output 他们的数据包 ID。

The most likely scenario is that one of your packets isn't being parsed completely, so you have leftover data that it tries to parse as a new packet.最可能的情况是您的一个数据包没有被完全解析,因此您有剩余的数据,它试图将其解析为一个新数据包。 I know this isn't a full answer but without your full program this is impossible for me to debug.我知道这不是一个完整的答案,但没有你的完整程序,我无法调试。

I would suggest creating a unit test for your packet handling logic, where you create a DataInputStream containing only a single packet.我建议为您的数据包处理逻辑创建一个单元测试,在其中创建一个仅包含单个数据包的 DataInputStream。 For each Packet, you check if it is handled correctly, and if you have any leftover data after processing.对于每个数据包,您检查它是否被正确处理,以及处理后是否有任何剩余数据。 This should enable you to find the problem.这应该使您能够发现问题。

Bro in my opinion You may have something else running on the same port - check the CMD with netstat -ano, also in Task Manager is possibility to look on current connections.在我看来,兄弟您可能在同一端口上运行了其他东西 - 使用 netstat -ano 检查 CMD,也可以在任务管理器中查看当前连接。 You may have multiple instances sending or listening on the same port or some other application using chosen port number - let's try changing port number and please tell us if something changed.您可能有多个实例在同一个端口或使用所选端口号的其他应用程序上发送或侦听 - 让我们尝试更改端口号,如果有变化,请告诉我们。 And one more: If anyone use readUTF, the other side must use writeUTF !!!还有一个:如果有人使用 readUTF,对方必须使用 writeUTF !!!

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

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