From 96903e4b7c3456a30b14dd140fc627e4025ce027 Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Sat, 25 Oct 2025 17:43:25 +0100 Subject: [PATCH] SocketConnection --- .../java/sd/protocol/SocketConnection.java | 110 +++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/main/src/main/java/sd/protocol/SocketConnection.java b/main/src/main/java/sd/protocol/SocketConnection.java index d56ad9c..0198242 100644 --- a/main/src/main/java/sd/protocol/SocketConnection.java +++ b/main/src/main/java/sd/protocol/SocketConnection.java @@ -1,5 +1,111 @@ package sd.protocol; -public class SocketConnection { +import java.io.Closeable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.Socket; +import java.net.UnknownHostException; -} +/** + * Wrapper class that simplifies communication via Sockets. + * * It encapsulates all stream logic (ObjectInputStream/ObjectOutputStream) + * so the rest of your code can simply "send" and "receive" objects + * that implement your MessageProtocol. + * * This is necessary to meet the requirement for inter-process communication + * (Intersections). + * * This class implements Closeable, so you can (and should) use it + * with a 'try-with-resources' block to ensure the socket is always closed. + */ +public class SocketConnection implements Closeable { + + private final Socket socket; + private final ObjectOutputStream outputStream; + private final ObjectInputStream inputStream; + + /** + * Constructor for the "Client" (who initiates the connection). + * Tries to connect to a process that is already listening (Server). + * + * @param host The host address (e.g., "localhost" from your simulation.properties) + * @param port The port (e.g., 8001 from your simulation.properties) + * @throws IOException If connection fails. + * @throws UnknownHostException If the host is not found. + */ + public SocketConnection(String host, int port) throws IOException, UnknownHostException { + this.socket = new Socket(host, port); + + // IMPORTANT: The order is crucial to prevent deadlocks when creating streams. + // The OutputStream (output stream) must be created first. + this.outputStream = new ObjectOutputStream(socket.getOutputStream()); + this.inputStream = new ObjectInputStream(socket.getInputStream()); + } + + /** + * Constructor for the "Server" (who accepts the connection). + * Receives a Socket that has already been accepted by a ServerSocket. + * + * @param acceptedSocket The Socket returned by serverSocket.accept(). + * @throws IOException If stream creation fails. + */ + public SocketConnection(Socket acceptedSocket) throws IOException { + this.socket = acceptedSocket; + + // IMPORTANT: The order is crucial. OutputStream (output stream) must be created first. + this.outputStream = new ObjectOutputStream(socket.getOutputStream()); + this.inputStream = new ObjectInputStream(socket.getInputStream()); + } + + /** + * Sends (serializes) a MessageProtocol object over the socket. + * + * @param message The "envelope" (which contains the Vehicle) to be sent. + * @throws IOException If writing to the stream fails. + */ + public void sendMessage(MessageProtocol message) throws IOException { + synchronized (outputStream) { + outputStream.writeObject(message); + outputStream.flush(); // Ensures the message is sent immediately. + } + } + + /** + * Tries to read (deserialize) a MessageProtocol object from the socket. + * This call is "blocked" until an object is received. + * + * @return The "envelope" (MessageProtocol) that was received. + * @throws IOException If the connection is lost or the stream is corrupted. + * @throws ClassNotFoundException If the received object is unknown. + */ + public MessageProtocol receiveMessage() throws IOException, ClassNotFoundException { + synchronized (inputStream) { + return (MessageProtocol) inputStream.readObject(); + } + } + + /** + * Closes the socket and all streams (Input and Output). + * It is called automatically if you use 'try-with-resources'. + */ + @Override + public void close() throws IOException { + try { + if (inputStream != null) inputStream.close(); + } catch (IOException e) { /* ignore */ } + + try { + if (outputStream != null) outputStream.close(); + } catch (IOException e) { /* ignore */ } + + if (socket != null && !socket.isClosed()) { + socket.close(); + } + } + + /** + * @return true if the socket is still connected. + */ + public boolean isConnected() { + return socket != null && socket.isConnected() && !socket.isClosed(); + } +} \ No newline at end of file