【问题标题】:Why does my UDP connection stop working?为什么我的 UDP 连接停止工作?
【发布时间】:2015-07-24 15:41:56
【问题描述】:

在创建 UDP 连接并从客户端连接到服务器后,它会随机停止工作。为什么会发生这种情况?

在使用“localhost”作为 IP 的同一台计算机上运行客户端和服务器时通常不会发生这种情况,但在同一网络上使用不同计算机时会发生这种情况。

当我一开始尝试使用不同的计算机进行连接时,它可以工作,但过了一段时间它就停止了;连接被“终止”。 另外,请忽略game.player 的东西,它只是我的一个玩家。

这是我的代码:

客户:

public class GameClient extends Thread {
  private InetAddress ipAddress;
  private DatagramSocket socket;
  private Main game;

  public GameClient(Main main, String ipAddress) {
    this.game = main;
    try {
      this.socket = new DatagramSocket();
      this.ipAddress = InetAddress.getByName(ipAddress);
    } catch (SocketException e) {
      e.printStackTrace();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
  }

  public void run() {
    while (true) {
      byte[] data = new byte[1024];
      DatagramPacket packet = new DatagramPacket(data, data.length);
      try {
        socket.receive(packet);
      } catch (IOException e) {
        e.printStackTrace();
      }
      String message = new String(packet.getData());
      message = message.trim();
      if (message.startsWith("00")) {
        System.out.println("Player connected. Got server response...");
        String msg = "01" + game.player.getPos();
        sendData(msg.getBytes());
      }
      if (message.startsWith("01")) {
        message = message.substring(2);
        List<String> coords = Arrays.asList(message.split(","));
        game.updateMP(coords);
        String msg = "01" + game.player.getPos();
        sendData(msg.getBytes());
      }

    }
  }

  public void sendData(byte[] data) {
    DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress,
        1331);
    try {
      socket.send(packet);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

我的服务器类:

public class GameServer extends Thread {
  private DatagramSocket socket;
  private Main game;

  public GameServer(Main main) {
    this.game = main;
    try {
      this.socket = new DatagramSocket(1331);
    } catch (SocketException e) {
      e.printStackTrace();
    }
  }

  public void run() {
    while (true) {
      byte[] data = new byte[1024];
      DatagramPacket packet = new DatagramPacket(data, data.length);
      try {
        socket.receive(packet);
      } catch (IOException e) {
        e.printStackTrace();
      }
      String message = new String(packet.getData());
      message = message.trim();
      if (message.startsWith("00")) {
        message = message.substring(2);
        game.playerConnected = true;
        sendData("00".getBytes(), packet.getAddress(), packet.getPort());
      }
      if (message.startsWith("01")) {
        message = message.substring(2);
        List<String> coords = Arrays.asList(message.split(","));
        game.updateMP(coords);
        String msg = "01" + game.player.getPos();
        sendData(msg.getBytes(), packet.getAddress(), packet.getPort());
      }

    }
  }

  public void sendData(byte[] data, InetAddress ipAddress, int port) {
    DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress,
        port);
    System.out.println(ipAddress + ", " + port);
    try {
      socket.send(packet);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

还有我的“主要”课程: (只是其中的一部分):

if (JOptionPane.showConfirmDialog(null, "Do you want to run the server?") == 0) {
  socketServer = new GameServer(this);
  socketServer.start();
  socketType = 0;
} else {
  socketClient = new GameClient(this, JOptionPane.showInputDialog(null, "IP:"));
  socketClient.start();
  socketClient.sendData("00".getBytes());
  socketType = 1;
}

【问题讨论】:

  • 异步网络 I/O 是一个已解决的问题。您自己做而不是使用 I/O 库有什么特别的原因吗?
  • 我想学习...刚开始的时候我记得我在 youtube 上看到这个人从头开始制作游戏.. 更准确地说是 DesignByZephyr。
  • @durron597 Tbh 我不确定您所说的“异步网络 I/O”是什么意思。我用谷歌搜索了它,据我所知,它是某种输入/输出的东西。如果更好,我应该实施它以及如何实施?
  • netty 这样的库会为您做很多低级别的数据包管理,让您有时间编写游戏而不是乱搞像DatagramSocket 这样的东西
  • 谢谢,我去看看。希望有人能够解决这个问题dou :)

标签: java networking udp


【解决方案1】:

看起来您的数据包流没有任何延迟。我的怀疑是,这大量的数据包只是溢出了网络,从而破坏了“连接”(UDP 是无连接的)。

让我们分解数据包流:

  • 服务器线程已创建(构造函数),绑定到端口 1331 (UDP)。
  • 服务器线程启动,第一步:监听套接字(阻塞)。
  • 客户端线程已创建,绑定到随机(空闲)端口。
  • 客户端线程启动,第一步:监听socket(阻塞)。
  • 主线程在客户端调用sendData("00"),当然工作正常。
  • 服务器线程收到“00”数据包,将 playerConnected 设置为 true 并返回“00”(通知客户端连接游戏成功)。然后服务器再次监听套接字。
  • 客户端线程接收到“00”包,并发送一个“01...”包。客户端再次监听套接字。
  • 服务器线程接收“01”数据包,更新其游戏对象并将“01”数据包发送回客户端(无延迟)。
  • 客户端线程收到“01”数据包,更新其游戏对象并返回“01”数据包(无延迟)

最后两个步骤无限重复,没有延迟

在同一台计算机上它工作得更好,因为环回接口是虚拟的,每秒可以处理更多的数据包,所以溢出发生的时间比在真实网络上要晚。

在网络游戏中更新玩家的位置是一个与网络游戏一样古老的问题。关于这个主题有很多文章。搜索例如用于“客户端位置预测”或某事。比如“在线游戏补偿延迟”,阅读 Quake2 源代码 (https://github.com/id-Software/Quake-2/blob/master/client/cl_pred.c) 等。

除此之外:避免使用字符串,避免创建大量新的字节数组,以提高性能。在 Java 中,您将受到垃圾收集器的惩罚。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多