我正在使用java进行多人游戏,我在这里确实遇到了一些问题。出于某种原因,我的数据报套接字将停止接收从客户端设置的数据包,即使根据控制台,它之前完全收到它们。我不太了解网络或使用套接字进行编程,所以这让我很难过。
这是我的代码:
服务器:
package server;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
import shared.BaseEntity;
import shared.MethodNotOverridenException;
import shared.Packet;
import shared.Player;
public class S_GameLoop implements Runnable{
//Constants
private static final int TICKS_PER_SECOND = 25;
private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
private static final int MAX_FRAMESKIP = 5;
private static final int SPAWN_COORD_X = 50;
private static final int SPAWN_COORD_Y = 50;
private Vector<S_Client> ClientList;
private Map<Integer, BaseEntity> EntityMap;
private AtomicInteger IDGenerator;
private boolean gameIsRunning = true;
private DatagramSocket socket;
byte[] recieveData = new byte[1024];
byte[] prevRecieveData = new byte[1024];
private int port;
private int loops;
public S_GameLoop(int port) {
ClientList = new Vector<S_Client>();
this.port = port;
IDGenerator = new AtomicInteger();
EntityMap = new HashMap<Integer, BaseEntity>();
}
private void Init() throws SocketException {
System.out.println("INIT");
socket = new DatagramSocket(port);
System.out.println("[Server] Create listen server on " + socket.getLocalAddress().getHostAddress() + " on port " + socket.getLocalPort());
socket.setSoTimeout(0);
}
private void Running() {
System.out.println("S_GameLoop staring");
long nextGameTick = System.currentTimeMillis();
DatagramPacket recievePacket = new DatagramPacket(recieveData, recieveData.length);
//GameLoop goes here
while(gameIsRunning) {
loops = 0;
//Receive the data
try {
socket.receive(recievePacket);
} catch (IOException e1) {
e1.printStackTrace();
}
while(System.currentTimeMillis() > nextGameTick && loops < MAX_FRAMESKIP) {
try {
Update(recievePacket);
} catch (MethodNotOverridenException | IOException e) {
System.err.println(e);
}
nextGameTick += TICKS_TO_SKIP;
loops++;
}
nextGameTick += TICKS_TO_SKIP;
loops++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void Update(DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
if(prevRecieveData != recieveData) {
parseData(formatData(recievePacket.getData()), recievePacket);
prevRecieveData = recieveData;
} else {
return;
}
}
public static Packet formatData(byte[] data) {
try {
if(data[1] == 0);
String tag = new String(Arrays.copyOfRange(data, 1, 8));
System.out.println("[Server] Recieved packet " + data[0] + " " + new String(tag));
return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
} catch (ArrayIndexOutOfBoundsException e) {
return new Packet((byte)0, new byte[0], new byte[0]);
}
}
private void parseData(Packet p, DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
if(p.getTag() == new byte[0]) {
System.out.println("[Server] Recieved NULL packet");
return;
}
switch (p.getTagAsString()) {
case "LGN_RQS": System.out.println("[Server] Login Request Recieved");
//Login was accepted
//Create a Client ref, and add it to the vector
S_Client newClient = new S_Client(recievePacket.getAddress(), recievePacket.getPort());
ClientList.add(newClient);
//Create a player and add it to Entity list
Player newPlayer = new Player(IDGenerator.getAndIncrement(), ClientList.indexOf(newClient));
EntityMap.put(newPlayer.getEntID(), newPlayer);
System.out.println("[Server] Created new Player with EID " + newPlayer.getEntID() + " and CID " + newPlayer.getCID());
//Send reply to Client that is logging in
sendData(new Packet((byte)2, "LGN_ACP".getBytes(), ("CID;" + ClientList.indexOf(newClient) + ";EID;" + newPlayer.getEntID()).getBytes()).getBytes(), newClient.getIp(), newClient.getPort());
//New Entity was created
//sendData(newPlayer.onCreate(this));
break;
case "HND_SHK": System.out.println("[Server] Handshake Recieved");
String fdata = new String(p.getData());
String[] data = fdata.split(";");
//Get client by client ID
S_Client c = ClientList.get(Integer.parseInt(data[1]));
c.setUsername(data[3]);
System.out.println("[Server] Set Client " + data[1] + "'s username to " + data[3]);
//Now spawn the player
sendData(new Packet((byte)9, "PLR_SPW".getBytes(), ("CID;" + data[1] + ";X;" + SPAWN_COORD_X + ";Y;" + SPAWN_COORD_Y).getBytes()).getBytes());
break;
}
}
public String[] byteArrayToStringArray(byte[] b) {
String fdata = new String(b);
return fdata.split(";");
}
public void createEntity(BaseEntity be) throws MethodNotOverridenException, IOException {
int ID = IDGenerator.incrementAndGet();
be.setEntID(ID);
EntityMap.put(ID, be);
sendData(be.onCreate(this));
}
public void sendData(byte[] sendData, InetAddress IP, int port) throws IOException {
System.out.println("[Server] Send packet " + sendData[0] + " " + new String(Arrays.copyOfRange(sendData, 1, 8)));
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IP, port);
socket.send(sendPacket);
}
public void sendData(byte[] sendData) throws IOException {
for (S_Client entry : ClientList) {
sendData(sendData, entry.getIp(), entry.getPort());
}
}
@Override
public void run() {
try {
Init();
Running();
} catch (SocketException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
}
客户端:
package client;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.Vector;
import shared.BaseEntity;
import shared.Packet;
import shared.Player;
public class C_GameLoop {
//How fast should the game update?
private static final int TICKS_PER_SECOND = 25;
//How many ticks should be skipped in order to run it at that speed?
//If it runs faster, then the Render() will be called more often
private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
//How many times should you skip rendering, if you have to?
private static final int MAX_FRAMESKIP = 5;
RenderCanvas rc;
InetAddress ServerIP;
private DatagramSocket socket;
private int port;
private boolean connectedToServer = false;
private boolean waitForData = false;
private String username = "Dummy";
byte[] sendPacket;
Vector<BaseEntity> RenderList;
Player player;
int fps = 0;
public C_GameLoop(RenderCanvas rc){
this.rc = rc;
RenderList = new Vector<BaseEntity>();
}
public boolean Connect(InetAddress ServerIP, int port) throws IOException {
this.port = port;
this.ServerIP = ServerIP;
socket = new DatagramSocket();
socket.setSoTimeout(4000);
DatagramPacket recieveData = new DatagramPacket(new byte[1024], new byte[1024].length);
System.out.println("[Client] Connecting to: " + ServerIP.getHostAddress() + ":" + port);
//Send a login request
sendData(new Packet((byte)1, "LGN_RQS".getBytes()).getBytes());
int retries = 0;
//Start the connect loop
while(!connectedToServer) {
try {
socket.receive(recieveData);
waitForData = false;
parseData(formatData(recieveData.getData()));
//recieveData.setData(new Packet((byte)0, new byte[0], new byte[0]).getBytes());
} catch (SocketTimeoutException e) {
if(waitForData = true && retries <= 4) {
System.out.println("[Client] Failed to recieve response from server, retrying");
parseData(formatData(recieveData.getData()));
retries++;
} else {
System.out.println("[Client] Failed to Connect to the server!");
return false;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
public void sendData(byte[] data) throws IOException {
System.out.println("[Client] Sent packet " + data[0] + " " + new String(Arrays.copyOfRange(data, 1, 8)));
DatagramPacket sendPacket = new DatagramPacket(data, data.length, ServerIP, port);
socket.send(sendPacket);
waitForData = true;
}
private void parseData(Packet p) throws IOException {
switch (p.getTagAsString()) {
case "LGN_ACP": System.out.println("[Client] Login Accepted");
//Get the data needed to create a new player from the packet
String fdata = new String(p.getData());
String[] data = fdata.split(";");
Player player = new Player(Integer.parseInt(data[1]), Integer.parseInt(data[3].trim()));
//Add it to the render list
this.player = player;
rc.getCamera().addDrawableEntity(player);
System.out.println("[Client] Player created with CID " + data[1] + " and EID " + data[3]);
//Send the handshake
System.out.println("[Client] Finshing Handshake...");
sendData(new Packet((byte)4, "HND_SHK".getBytes(), ("CID;" + player.getCID() + ";Username;" + username).getBytes()).getBytes());
break;
case "PLR_SPW": System.out.println("[Client] Spawn Recieved");
//Get the coords
String[] spawn_data = byteArrayToStringArray(p.getData());
this.player.setX(Integer.parseInt(spawn_data[3]));
this.player.setY(Integer.parseInt(spawn_data[5].trim()));
sendData(new Packet((byte)0, "KEP_ALV".getBytes()).getBytes());
break;
}
}
public String[] byteArrayToStringArray(byte[] b) {
String fdata = new String(b);
return fdata.split(";");
}
/*
* Formats data into a packet
*/
public static Packet formatData(byte[] data) {
try {
if(data[1] == 0);
String tag = new String(Arrays.copyOfRange(data, 1, 8));
System.out.println("[Client] Recieved packet " + data[0] + " " + new String(tag));
return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
} catch (ArrayIndexOutOfBoundsException e) {
return new Packet((byte)0, new byte[0], new byte[0]);
}
}
}
运行代码时的控制台输出:
INIT
[Server] Create listen server on 0.0.0.0 on port 4334
S_GameLoop staring
[Client] Connecting to: 127.0.0.1:4334
[Client] Sent packet 1 LGN_RQS
[Server] Recieved packet 1 LGN_RQS
[Server] Login Request Recieved
[Server] Created new Player with EID 0 and CID 0
[Server] Send packet 2 LGN_ACP
[Client] Recieved packet 2 LGN_ACP
[Client] Login Accepted
[Client] Player created with CID 0 and EID 0
[Client] Finshing Handshake...
[Client] Sent packet 4 HND_SHK
[Client] Failed to recieve response from server, retrying
(Same lines as previous 6 just repeat 4 times)
[Client] Failed to Connect to the server!
任何想法?
答案 0 :(得分:1)
看起来您的Server
类被设计为用作某个工作线程的Runnable
。
我怀疑问题是run()
方法由于未捕获的异常而死亡,并且工作线程正在终止。
我建议您配置默认的未捕获异常处理程序,以(至少)记录致命异常的堆栈跟踪。有关详细信息,请参阅Thread
javadoc。