为什么我的 UDP 连接停止工作?
Why does my UDP connection stop working?
创建UDP连接并从客户端连接到服务器后,它随机停止工作。为什么会这样?
当 运行 客户端和服务器在同一台计算机上使用 "localhost" 作为 IP 时,通常不会发生这种情况,但是当在同一网络上使用不同的计算机时,就会发生这种情况。
当我尝试使用不同的计算机进行连接时,一开始它可以工作,但一段时间后它就停止了;连接是 "terminated"。
另外,忽略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();
}
}
}
我的服务器class:
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();
}
}
}
还有我的 "Main" class:
(只是一部分):
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;
}
看起来您的数据包流没有任何延迟。我的怀疑是,大量的数据包溢出了网络,从而破坏了 "connection"(UDP 是无连接的)。
让我们分解数据包流:
- 服务器线程已创建(构造函数),绑定到端口 1331 (UDP)。
- 服务器线程启动,第一步:监听套接字(阻塞)。
- 客户端线程已创建,绑定到随机(空闲)端口。
- 客户端线程启动,第一步:监听套接字(阻塞)。
- 主线程在客户端调用 sendData("00"),这当然没问题。
- 服务器线程收到“00”数据包,将playerConnected设置为true并发回“00”(通知客户端连接游戏成功)。然后服务器再次监听套接字。
- 客户端线程收到“00”数据包,并发送“01...”数据包。客户端再次监听套接字。
- 服务器线程接收“01”数据包,更新其游戏对象并将“01”数据包发送回客户端(无延迟)。
- 客户端线程收到“01”数据包,更新其游戏对象并发回“01”数据包(无延迟)
最后两个步骤无限重复,没有延迟。
在同一台计算机上效果更好,因为环回接口是虚拟的,每秒可以处理更多的数据包,所以溢出发生的时间比在真实网络上要晚。
在网络游戏中更新玩家位置是一个与网络游戏一样古老的问题。有很多关于该主题的文章。搜索例如对于 "client side position prediction" 或某事。喜欢 "online game compensate latency",阅读 Quake2 源代码 (https://github.com/id-Software/Quake-2/blob/master/client/cl_pred.c) 等
除此之外:避免使用字符串,避免创建大量新的字节数组,以提高性能。在 Java 之后,您将受到垃圾收集器的惩罚。
创建UDP连接并从客户端连接到服务器后,它随机停止工作。为什么会这样?
当 运行 客户端和服务器在同一台计算机上使用 "localhost" 作为 IP 时,通常不会发生这种情况,但是当在同一网络上使用不同的计算机时,就会发生这种情况。
当我尝试使用不同的计算机进行连接时,一开始它可以工作,但一段时间后它就停止了;连接是 "terminated"。
另外,忽略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();
}
}
}
我的服务器class:
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();
}
}
}
还有我的 "Main" class: (只是一部分):
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;
}
看起来您的数据包流没有任何延迟。我的怀疑是,大量的数据包溢出了网络,从而破坏了 "connection"(UDP 是无连接的)。
让我们分解数据包流:
- 服务器线程已创建(构造函数),绑定到端口 1331 (UDP)。
- 服务器线程启动,第一步:监听套接字(阻塞)。
- 客户端线程已创建,绑定到随机(空闲)端口。
- 客户端线程启动,第一步:监听套接字(阻塞)。
- 主线程在客户端调用 sendData("00"),这当然没问题。
- 服务器线程收到“00”数据包,将playerConnected设置为true并发回“00”(通知客户端连接游戏成功)。然后服务器再次监听套接字。
- 客户端线程收到“00”数据包,并发送“01...”数据包。客户端再次监听套接字。
- 服务器线程接收“01”数据包,更新其游戏对象并将“01”数据包发送回客户端(无延迟)。
- 客户端线程收到“01”数据包,更新其游戏对象并发回“01”数据包(无延迟)
最后两个步骤无限重复,没有延迟。
在同一台计算机上效果更好,因为环回接口是虚拟的,每秒可以处理更多的数据包,所以溢出发生的时间比在真实网络上要晚。
在网络游戏中更新玩家位置是一个与网络游戏一样古老的问题。有很多关于该主题的文章。搜索例如对于 "client side position prediction" 或某事。喜欢 "online game compensate latency",阅读 Quake2 源代码 (https://github.com/id-Software/Quake-2/blob/master/client/cl_pred.c) 等
除此之外:避免使用字符串,避免创建大量新的字节数组,以提高性能。在 Java 之后,您将受到垃圾收集器的惩罚。