Files
SD/main/src/main/java/sd/coordinator/SocketClient.java

125 lines
4.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 wont 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());
}
}