Some more improvements to socket handling.

This commit is contained in:
Andrew Lalis 2022-04-09 12:59:53 +02:00
parent 9be9a15fa0
commit dfc7ac6978
3 changed files with 61 additions and 17 deletions

View File

@ -1,17 +1,22 @@
package nl.andrewl.starship_arena.server;
import lombok.Getter;
import nl.andrewl.starship_arena.server.model.Arena;
import java.io.IOException;
import java.net.Socket;
import java.util.UUID;
public class ClientManager extends Thread {
private final Arena arena;
private final Socket clientSocket;
@Getter
private final UUID clientId;
public ClientManager(Arena arena, Socket clientSocket) {
public ClientManager(Arena arena, Socket clientSocket, UUID id) {
this.arena = arena;
this.clientSocket = clientSocket;
this.clientId = id;
}
public void shutdown() {
@ -24,7 +29,7 @@ public class ClientManager extends Thread {
@Override
public void run() {
while (clientSocket.isConnected() && !clientSocket.isClosed()) {
while (!clientSocket.isClosed()) {
}
}

View File

@ -3,12 +3,15 @@ package nl.andrewl.starship_arena.server;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import nl.andrewl.starship_arena.server.data.ArenaStore;
import nl.andrewl.starship_arena.server.model.Arena;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import javax.annotation.PreDestroy;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
@ -48,6 +51,17 @@ public class SocketGateway implements Runnable {
new Thread(this).start();
}
@PreDestroy
public void shutdown() {
try {
log.info("Shutting down Socket Gateway.");
serverSocket.close();
serverUdpSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
@ -56,27 +70,52 @@ public class SocketGateway implements Runnable {
serverUdpSocket.bind(new InetSocketAddress(host, udpPort));
log.info("Socket Gateway bound UDP on {}:{}", host, udpPort);
} catch (IOException e) {
e.printStackTrace();
return;
throw new IllegalStateException(e); // Quit; server cannot run if these sockets can't bind.
}
while (!serverSocket.isClosed()) {
try {
Socket clientSocket = serverSocket.accept();
processIncomingConnection(clientSocket);
new Thread(() -> processIncomingConnection(clientSocket)).start();
} catch (IOException e) {
e.printStackTrace();
if (!e.getMessage().equalsIgnoreCase("Socket closed")) e.printStackTrace();
}
}
}
private void processIncomingConnection(Socket clientSocket) throws IOException {
var din = new DataInputStream(clientSocket.getInputStream());
UUID arenaId = new UUID(din.readLong(), din.readLong());
var oa = arenaStore.getById(arenaId);
if (oa.isPresent()) {
new ClientManager(oa.get(), clientSocket).start();
} else {
clientSocket.close();
/**
* Logic to do to initialize a client TCP connection, which involves getting
* some basic information about the connection, such as which arena the
* client is connecting to. A {@link ClientManager} is then started to
* handle further communication with the client.
* @param clientSocket The socket to the client.
*/
private void processIncomingConnection(Socket clientSocket) {
try (
var in = new DataInputStream(clientSocket.getInputStream());
var out = new DataOutputStream(clientSocket.getOutputStream())
) {
UUID arenaId = new UUID(in.readLong(), in.readLong());
UUID clientId;
boolean reconnecting = in.readBoolean();
if (reconnecting) {
clientId = new UUID(in.readLong(), in.readLong());
} else {
clientId = UUID.randomUUID();
}
var oa = arenaStore.getById(arenaId);
if (oa.isPresent()) {
Arena arena = oa.get();
ClientManager clientManager = new ClientManager(arena, clientSocket, clientId);
arena.registerClient(clientManager);
out.writeBoolean(true);
clientManager.start();
} else {
out.writeBoolean(false);
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -42,11 +42,11 @@ public class Arena {
return currentStage;
}
public void registerClient(UUID id, ClientManager clientManager) {
if (clients.containsKey(id)) {
public void registerClient(ClientManager clientManager) {
if (clients.containsKey(clientManager.getClientId())) {
clientManager.shutdown();
} else {
clients.put(id, clientManager);
clients.put(clientManager.getClientId(), clientManager);
}
}