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