mirror of
https://github.com/davidalves04/Trabalho-Pratico-SD.git
synced 2025-12-08 12:33:31 +00:00
125 lines
4.0 KiB
Java
125 lines
4.0 KiB
Java
package sd.coordinator;
|
||
|
||
import java.io.IOException;
|
||
import java.io.OutputStream;
|
||
import java.net.Socket;
|
||
|
||
import sd.model.Message;
|
||
import sd.serialization.MessageSerializer;
|
||
import sd.serialization.SerializationException;
|
||
import sd.serialization.SerializerFactory;
|
||
|
||
/**
|
||
* Socket client for communication with a single intersection process.
|
||
*
|
||
* Handles a persistent TCP connection to one intersection,
|
||
* providing a simple way to send serialized messages.
|
||
*/
|
||
public class SocketClient {
|
||
|
||
private final String intersectionId;
|
||
private final String host;
|
||
private final int port;
|
||
private Socket socket;
|
||
private OutputStream outputStream;
|
||
private MessageSerializer serializer;
|
||
|
||
/**
|
||
* Creates a new SocketClient for a given intersection.
|
||
*
|
||
* @param intersectionId Intersection ID (ex. "Cr1")
|
||
* @param host Host address (ex. "localhost")
|
||
* @param port Port number
|
||
*/
|
||
public SocketClient(String intersectionId, String host, int port) {
|
||
this.intersectionId = intersectionId;
|
||
this.host = host;
|
||
this.port = port;
|
||
this.serializer = SerializerFactory.createDefault();
|
||
}
|
||
|
||
/**
|
||
* Connects to the intersection process via TCP.
|
||
*
|
||
* @throws IOException if the connection cannot be established
|
||
*/
|
||
|
||
public void connect() throws IOException {
|
||
try {
|
||
socket = new Socket(host, port);
|
||
outputStream = socket.getOutputStream();
|
||
System.out.println("Connected to " + intersectionId + " at " + host + ":" + port);
|
||
} catch (IOException e) {
|
||
System.err.println("Failed to connect to " + intersectionId + " at " + host + ":" + port);
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Sends a message to the connected intersection.
|
||
* The message is serialized and written over the socket.
|
||
*
|
||
* @param message The message to send
|
||
* @throws SerializationException if serialization fails
|
||
* @throws IOException if the socket write fails
|
||
*/
|
||
public void send(Message message) throws SerializationException, IOException {
|
||
if (socket == null || socket.isClosed()) {
|
||
throw new IOException("Socket is not connected to " + intersectionId);
|
||
}
|
||
|
||
try {
|
||
byte[] data = serializer.serialize(message);
|
||
|
||
// Prefix with message length (so receiver knows how much to read)
|
||
int length = data.length;
|
||
outputStream.write((length >> 24) & 0xFF);
|
||
outputStream.write((length >> 16) & 0xFF);
|
||
outputStream.write((length >> 8) & 0xFF);
|
||
outputStream.write(length & 0xFF);
|
||
|
||
outputStream.write(data);
|
||
outputStream.flush();
|
||
|
||
} catch (SerializationException | IOException e) {
|
||
System.err.println("Error sending message to " + intersectionId + ": " + e.getMessage());
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Closes the socket connection safely.
|
||
* Calling it multiple times won’t cause issues.
|
||
*/
|
||
public void close() {
|
||
try {
|
||
if (outputStream != null) {
|
||
outputStream.close();
|
||
}
|
||
if (socket != null && !socket.isClosed()) {
|
||
socket.close();
|
||
System.out.println("Closed connection to " + intersectionId);
|
||
}
|
||
} catch (IOException e) {
|
||
System.err.println("Error closing connection to " + intersectionId + ": " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @return true if connected and socket is open, false otherwise
|
||
*/
|
||
public boolean isConnected() {
|
||
return socket != null && socket.isConnected() && !socket.isClosed();
|
||
}
|
||
|
||
public String getIntersectionId() {
|
||
return intersectionId;
|
||
}
|
||
|
||
@Override
|
||
public String toString() {
|
||
return String.format("SocketClient[intersection=%s, host=%s, port=%d, connected=%s]",
|
||
intersectionId, host, port, isConnected());
|
||
}
|
||
}
|