我正在为多人游戏创建简单的客户端服务器通信。服务器应该只向所有其他连接的播放器广播消息。我希望每个玩家都有一个单独的线程,这就是我做到的:
服务器:
public class Server extends Thread {
private static final Logger LOGGER = Logger.getLogger(Server.class.getName());
private ServerSocket serverSocket;
private static final int SERVER_PORT = 6066;
public Server(int port) {
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Couldn't start server");
}
}
public void run() {
while (true) {
try {
System.out.println("LISTENING...");
Socket clientSocket = serverSocket.accept();
System.out.println("GOT CONNECTION");
PlayerThread playerThread = new PlayerThread(clientSocket);
playerThread.start();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Exception occured on server");
break;
}
}
try {
serverSocket.close();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Server is down.");
}
}
public static void main(String[] args) {
Thread t = new Server(SERVER_PORT);
t.start();
}
}
PlayerThread:
public class PlayerThread extends Thread {
private static final Logger LOGGER = Logger.getLogger(PlayerThread.class.getName());
private static List<PlayerThread> players = new ArrayList<PlayerThread>(4);
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private String playerName;
private ObjectMapper objectMapper = new ObjectMapper();
public PlayerThread(Socket socket) throws IOException {
try {
this.socket = socket;
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
LOGGER.log(Level.INFO, "Couldn't read stream");
}
}
@Override
public void run() {
while (true) {
try {
String inputMessage = in.readUTF();
System.out.println("GOT: " + inputMessage);
JsonNode jsonNode = objectMapper.readTree(inputMessage);
String senderName = jsonNode.get("senderName").asText();
if (!players.contains(this)) {
playerName = senderName;
players.add(this);
players.forEach((p) -> System.out.println(p));
}
for (PlayerThread p : players) {
p.getOut().writeUTF(inputMessage);
}
} catch (IOException e) {
LOGGER.log(Level.INFO, "Player disconnected: " + playerName);
players.remove(this);
break;
}
}
try {
socket.close();
} catch (IOException e) {
LOGGER.log(Level.INFO, "Couldn't close stream");
}
}
@Override
public String toString() {
return "Player [name=" + playerName + "]";
}
public DataInputStream getIn() {
return in;
}
public DataOutputStream getOut() {
return out;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((playerName == null) ? 0 : playerName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PlayerThread other = (PlayerThread) obj;
if (playerName == null) {
if (other.playerName != null)
return false;
} else if (!playerName.equals(other.playerName))
return false;
return true;
}
}
在客户端,我创建套接字并发送JSON:
playerSocket = new Socket(SERVER_ADDRESS, SERVER_PORT);
in = new DataInputStream(playerSocket.getInputStream());
out = new DataOutputStream(playerSocket.getOutputStream());
out.writeUTF(JSONConverter.ObjectToJSON(message));
问题是,对于每个连接,都会创建新线程和新套接字。我可以做另一个Player类并将它们保存在List中,但它仍然意味着每个连接都创建它自己的线程。 来自播放器的消息每100ms发送一次,因此在1s后我将有10个线程,这显然是错误的。我该怎么办?