From 7b90a813650c452d8a8b255b47c384715587d8f7 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 26 Feb 2025 16:59:15 +0100 Subject: [PATCH] feat: udp --- app/src/main/java/network/Connexion.java | 39 +++++++-------- .../main/java/network/ConnexionThread.java | 44 ---------------- .../java/network/client/ClientConnexion.java | 39 +++++++++++++-- app/src/main/java/network/server/Server.java | 34 +++++++------ .../network/server/ServerAcceptThread.java | 36 ------------- .../java/network/server/ServerConnexion.java | 25 ++++------ .../java/network/server/ServerReadThread.java | 50 +++++++++++++++++++ 7 files changed, 130 insertions(+), 137 deletions(-) delete mode 100644 app/src/main/java/network/ConnexionThread.java delete mode 100644 app/src/main/java/network/server/ServerAcceptThread.java create mode 100644 app/src/main/java/network/server/ServerReadThread.java diff --git a/app/src/main/java/network/Connexion.java b/app/src/main/java/network/Connexion.java index 1b1e285..bef0f43 100644 --- a/app/src/main/java/network/Connexion.java +++ b/app/src/main/java/network/Connexion.java @@ -1,40 +1,37 @@ package network; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; -import java.net.Socket; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; import network.protocol.Packet; import network.protocol.PacketVisitor; public abstract class Connexion implements PacketVisitor { - final Socket socket; - private final ObjectOutputStream objectOutputStream; - private final ConnexionThread connexionThread; + protected final DatagramSocket socket; + protected final InetSocketAddress address; - public Connexion(Socket socket) throws IOException { + public Connexion(DatagramSocket socket, InetSocketAddress address) { this.socket = socket; - this.objectOutputStream = new ObjectOutputStream(this.socket.getOutputStream()); - this.connexionThread = new ConnexionThread(this); - this.connexionThread.start(); + this.address = address; } - public boolean isClosed() { - return this.socket.isClosed(); - } - - public synchronized void sendPacket(Packet packet) { + public void sendPacket(Packet packet) { + System.out.println("Sending " + packet); try { - objectOutputStream.writeObject(packet); - objectOutputStream.flush(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(stream); + oos.writeObject(packet); + oos.flush(); + byte[] data = stream.toByteArray(); + DatagramPacket dataPacket = new DatagramPacket(data, data.length, this.address.getAddress(), this.address.getPort()); + this.socket.send(dataPacket); } catch (IOException e) { - System.err.println("Error while sending packet ! " + e.getLocalizedMessage()); - close(); + e.printStackTrace(); } } - - public void close() { - this.connexionThread.cancel(); - } } diff --git a/app/src/main/java/network/ConnexionThread.java b/app/src/main/java/network/ConnexionThread.java deleted file mode 100644 index 17b0584..0000000 --- a/app/src/main/java/network/ConnexionThread.java +++ /dev/null @@ -1,44 +0,0 @@ -package network; - -import java.io.IOException; -import java.io.ObjectInputStream; - -import network.protocol.Packet; - -public class ConnexionThread extends Thread { - - private final Connexion connexion; - private final ObjectInputStream objectInputStream; - - public ConnexionThread(Connexion connexion) throws IOException { - this.connexion = connexion; - this.objectInputStream = new ObjectInputStream(this.connexion.socket.getInputStream()); - } - - @Override - public void run() { - while (!interrupted()) { - try { - // System.out.println(objectInputStream.available()); - Object o = objectInputStream.readObject(); - if (o instanceof Packet packet) { - connexion.visit(packet); - } - } catch (ClassNotFoundException | IOException e) { - e.printStackTrace(); - this.connexion.close(); - break; - } - } - } - - public void cancel() { - try { - objectInputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - interrupt(); - } - -} diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java index c0f04a8..3b8ab58 100644 --- a/app/src/main/java/network/client/ClientConnexion.java +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -1,11 +1,16 @@ package network.client; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.net.Socket; +import java.io.ObjectInputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; import java.net.UnknownHostException; import game.Player; import network.Connexion; +import network.protocol.Packet; import network.protocol.packets.ChangeCellPacket; import network.protocol.packets.ConnexionInfoPacket; import network.protocol.packets.DisconnectPacket; @@ -16,23 +21,47 @@ import network.protocol.packets.PlayerJoinPacket; import network.protocol.packets.PlayerLeavePacket; import network.protocol.packets.StartGamePacket; import network.protocol.packets.UpdatePlayerScorePacket; +import network.server.ServerConnexion; import sudoku.io.SudokuSerializer; public class ClientConnexion extends Connexion { private final Client client; + private final Thread readThread; public ClientConnexion(String address, short port, Client client) throws UnknownHostException, IOException { - super(new Socket(address, port)); + super(new DatagramSocket(), new InetSocketAddress(address, port)); this.client = client; + this.readThread = new Thread(this::readPackets); + this.readThread.start(); + } + + private void readPackets() { + while (!Thread.interrupted()) { + try { + byte[] buffer = new byte[1024 * 10]; + DatagramPacket dataPacket = new DatagramPacket(buffer, buffer.length); + this.socket.receive(dataPacket); + System.out.println(dataPacket.getLength()); + + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(dataPacket.getData())); + Packet packet = (Packet) ois.readObject(); + + visit(packet); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } } - @Override public void close() { - if (!this.isClosed()) { - super.close(); + if (!this.socket.isClosed()) { sendPacket(new DisconnectPacket("")); client.onDisconnect.emit(); + this.readThread.interrupt(); + this.socket.close(); } } diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java index 7c746be..302b4de 100644 --- a/app/src/main/java/network/server/Server.java +++ b/app/src/main/java/network/server/Server.java @@ -1,14 +1,15 @@ package network.server; import java.io.IOException; -import java.net.ServerSocket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; import java.time.Instant; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import game.Game; -import game.Player; import game.Game.GameState; +import game.Player; import network.protocol.Packet; import network.protocol.packets.EndGamePacket; import network.protocol.packets.StartGamePacket; @@ -17,17 +18,17 @@ import sudoku.structure.MultiDoku; public class Server { - final ServerSocket serverSocket; - final List connexions; - private final ServerAcceptThread acceptThread; + final DatagramSocket serverSocket; + final Map connexions; + private final ServerReadThread acceptThread; private final ServerLogicThread logicThread; private final Game game; private int nextPlayerId = 0; public Server(short port) throws IOException { - this.serverSocket = new ServerSocket(port); - this.connexions = new ArrayList<>(); - this.acceptThread = new ServerAcceptThread(this); + this.serverSocket = new DatagramSocket(port); + this.connexions = new HashMap<>(); + this.acceptThread = new ServerReadThread(this); this.acceptThread.start(); this.logicThread = new ServerLogicThread(this); this.logicThread.start(); @@ -35,7 +36,7 @@ public class Server { } public void broadcastPacket(Packet packet) { - for (ServerConnexion connexion : this.connexions) { + for (ServerConnexion connexion : this.connexions.values()) { connexion.sendPacket(packet); } } @@ -50,8 +51,9 @@ public class Server { } private void checkConnexions() { - for (var it = connexions.iterator(); it.hasNext();) { - ServerConnexion connexion = it.next(); + for (var it = connexions.entrySet().iterator(); it.hasNext();) { + var entry = it.next(); + ServerConnexion connexion = entry.getValue(); if (!connexion.update()) { connexion.close(); connexion.nukeConnection(); @@ -68,10 +70,10 @@ public class Server { public void stop() { this.acceptThread.cancel(); this.logicThread.cancel(); - for (ServerConnexion connexion : this.connexions) { + for (ServerConnexion connexion : this.connexions.values()) { connexion.nukeConnection(); - connexion.close(); } + this.serverSocket.close(); } public Player addPlayer(String pseudo) { @@ -88,7 +90,7 @@ public class Server { public void startGame(MultiDoku doku, long gameDuration) { Instant now = Instant.now(); this.game.startGame(doku, now, gameDuration); - for (ServerConnexion connexion : this.connexions) { + for (ServerConnexion connexion : this.connexions.values()) { connexion.setSudoku(doku.clone()); } broadcastPacket(new StartGamePacket(SudokuSerializer.serializeSudoku(doku).toString(), now, gameDuration)); diff --git a/app/src/main/java/network/server/ServerAcceptThread.java b/app/src/main/java/network/server/ServerAcceptThread.java deleted file mode 100644 index 61800db..0000000 --- a/app/src/main/java/network/server/ServerAcceptThread.java +++ /dev/null @@ -1,36 +0,0 @@ -package network.server; - -import java.io.IOException; -import java.net.Socket; - -public class ServerAcceptThread extends Thread { - - private final Server server; - - public ServerAcceptThread(Server server) { - this.server = server; - } - - public void cancel() { - try { - this.server.serverSocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - interrupt(); - } - - @Override - public void run() { - try { - while(!interrupted()) { - Socket newConnection = this.server.serverSocket.accept(); - ServerConnexion serverConnection = new ServerConnexion(newConnection, this.server); - this.server.connexions.add(serverConnection); - } - } catch(IOException e) { - // e.printStackTrace(); - } - } - -} diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java index 68de01b..df5fa2c 100644 --- a/app/src/main/java/network/server/ServerConnexion.java +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -1,11 +1,11 @@ package network.server; import java.io.IOException; -import java.net.Socket; +import java.net.InetSocketAddress; import game.Game; -import game.Player; import game.Game.GameState; +import game.Player; import network.Connexion; import network.protocol.packets.ChangeCellPacket; import network.protocol.packets.ConnexionInfoPacket; @@ -29,14 +29,14 @@ public class ServerConnexion extends Connexion { private Player player = null; private MultiDoku doku; - public ServerConnexion(Socket socket, Server server) throws IOException { - super(socket); + public ServerConnexion(InetSocketAddress remoteAddress, Server server) throws IOException { + super(server.serverSocket, remoteAddress); this.server = server; this.keepAliveHandler = new KeepAliveHandler(this); } public boolean update() { - if (shouldClose || isClosed()) + if (shouldClose) return false; return this.keepAliveHandler.update(); } @@ -49,15 +49,6 @@ public class ServerConnexion extends Connexion { } } - @Override - public synchronized void close() { - if (shouldClose) - return; - super.close(); - shouldClose = true; - System.out.println("[Server] Closing connexion !"); - } - private void finishLogin() { // send players that have already joined (excluding this one) for (Player p : this.server.getGame().getPlayers().values()) { @@ -87,7 +78,7 @@ public class ServerConnexion extends Connexion { @Override public void visitPacket(DisconnectPacket packet) { - close(); + //TODO: close connexion } @Override @@ -164,4 +155,8 @@ public class ServerConnexion extends Connexion { this.server.broadcastPacket(new UpdatePlayerScorePacket(player.getId(), player.getRemainingCells())); } + public void close() { + this.shouldClose = true; + } + } diff --git a/app/src/main/java/network/server/ServerReadThread.java b/app/src/main/java/network/server/ServerReadThread.java new file mode 100644 index 0000000..0a64974 --- /dev/null +++ b/app/src/main/java/network/server/ServerReadThread.java @@ -0,0 +1,50 @@ +package network.server; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.DatagramPacket; +import java.net.InetSocketAddress; + +import network.protocol.Packet; + +public class ServerReadThread extends Thread { + + private final Server server; + + public ServerReadThread(Server server) { + this.server = server; + } + + public void cancel() { + this.server.serverSocket.close(); + interrupt(); + } + + @Override + public void run() { + try { + while (!interrupted()) { + byte[] buffer = new byte[1024]; + DatagramPacket dataPacket = new DatagramPacket(buffer, buffer.length); + this.server.serverSocket.receive(dataPacket); + + InetSocketAddress address = new InetSocketAddress(dataPacket.getAddress(), dataPacket.getPort()); + + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(dataPacket.getData())); + Packet packet = (Packet) ois.readObject(); + + if (!this.server.connexions.containsKey(dataPacket.getSocketAddress())) { + this.server.connexions.put(address, new ServerConnexion(address, server)); + } + + this.server.connexions.get(address).visit(packet); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + +}