Socket与RMI通信的火灾报警传感器系统技术咨询
Alright, let's break down this fire alarm sensor system's Socket-RMI collaborative architecture and implementation step by step. I’ve built similar IoT monitoring pipelines before, so I’ll walk you through the key components with practical code snippets and real-world considerations.
First, let’s map the data flow to understand how Socket and RMI play to their strengths:
- Socket Layer: Handles real-time, high-concurrency raw data transmission from sensors to a server, which writes the data to a text file (or a more efficient intermediate store). Socket is ideal here because it’s lightweight and low-latency for continuous data pushes from distributed sensors.
- RMI Layer: Acts as a service layer that reads the stored data and exposes business-friendly methods to monitoring clients (like querying connected sensor counts or fetching latest readings). RMI eliminates the need to reinvent remote method calls in Java, making client-server interactions clean and maintainable.
This layer has two core parts: the sensor-side Socket client and the server that receives and stores data.
Sensor Socket Client (Data Collection)
Each sensor runs this client to collect metrics and send them to the Socket server. We’ll use a long-lived connection for efficiency:
import java.io.OutputStream; import java.net.Socket; import java.util.Random; public class FireAlarmSensorClient { private static final String SERVER_IP = "your-server-ip"; private static final int SERVER_PORT = 8888; private final String sensorId; public FireAlarmSensorClient(String sensorId) { this.sensorId = sensorId; } public void startDataCollection() { try (Socket socket = new Socket(SERVER_IP, SERVER_PORT); OutputStream os = socket.getOutputStream()) { Random random = new Random(); while (true) { // Simulate real sensor data: temp (0-100°C), CO2 (400-5000ppm) double temperature = 22 + random.nextDouble() * 28; int co2Level = 400 + random.nextInt(4600); // Standardize data format for easy parsing: [sensorId],[temp],[co2] String payload = String.format("%s,%.1f,%d\n", sensorId, temperature, co2Level); os.write(payload.getBytes()); os.flush(); Thread.sleep(5000); // Send data every 5 seconds } } catch (Exception e) { System.err.printf("Sensor %s lost connection: %s%n", sensorId, e.getMessage()); } } public static void main(String[] args) { new FireAlarmSensorClient("SENSOR-001").startDataCollection(); } }
Pro tip: Assign unique sensor IDs upfront—this makes it easy to track individual devices and count active connections later.
Socket Data Collector Server (Receive & Store)
This server listens for incoming sensor connections, processes data, and writes it to a text file. Use a thread pool to handle multiple concurrent sensors:
import java.io.BufferedWriter; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SocketDataCollectorServer { private static final int PORT = 8888; private static final String DATA_STORE = "sensor_readings.txt"; private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(PORT)) { System.out.printf("Socket collector running on port %d%n", PORT); while (true) { Socket clientSocket = serverSocket.accept(); THREAD_POOL.submit(new SensorConnectionHandler(clientSocket)); } } catch (Exception e) { System.err.printf("Socket server failed: %s%n", e.getMessage()); } } static class SensorConnectionHandler implements Runnable { private final Socket clientSocket; public SensorConnectionHandler(Socket socket) { this.clientSocket = socket; } @Override public void run() { try (InputStream is = clientSocket.getInputStream(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new java.io.FileOutputStream(DATA_STORE, true)))) { byte[] buffer = new byte[1024]; int bytesRead; System.out.printf("New sensor connected: %s%n", clientSocket.getInetAddress()); while ((bytesRead = is.read(buffer)) != -1) { String data = new String(buffer, 0, bytesRead).trim(); writer.write(data + "\n"); writer.flush(); System.out.printf("Saved data: %s%n", data); } } catch (Exception e) { System.out.printf("Sensor disconnected: %s%n", clientSocket.getInetAddress()); } finally { try { clientSocket.close(); } catch (Exception ignored) {} } } } }
Note: Using append mode (true in FileOutputStream) ensures we don’t overwrite existing data. For high-throughput scenarios, consider batching writes instead of flushing every time.
RMI lets monitoring clients call remote methods directly, so we’ll build a service that exposes sensor-related queries.
Step 1: Define the RMI Remote Interface
All remote methods must throw RemoteException and the interface must extend Remote:
import java.rmi.Remote; import java.rmi.RemoteException; import java.util.List; public interface SensorMonitorService extends Remote { // Get count of unique connected sensors int getConnectedSensorCount() throws RemoteException; // Fetch the latest N sensor readings List<String> getLatestReadings(int count) throws RemoteException; }
Step 2: Implement the RMI Service
This class reads from the text file (or a cached store) and implements the interface methods:
import java.io.BufferedReader; import java.io.FileReader; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class SensorMonitorServiceImpl extends UnicastRemoteObject implements SensorMonitorService { private static final String DATA_STORE = "sensor_readings.txt"; protected SensorMonitorServiceImpl() throws RemoteException { super(); } @Override public int getConnectedSensorCount() throws RemoteException { Set<String> sensorIds = new HashSet<>(); try (BufferedReader reader = new BufferedReader(new FileReader(DATA_STORE))) { String line; while ((line = reader.readLine()) != null) { if (!line.isEmpty()) { sensorIds.add(line.split(",")[0]); } } } catch (Exception e) { e.printStackTrace(); return 0; } // For better accuracy, track active connections in the Socket server and expose it via a getter return sensorIds.size(); } @Override public List<String> getLatestReadings(int count) throws RemoteException { List<String> allReadings = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new FileReader(DATA_STORE))) { String line; while ((line = reader.readLine()) != null) { if (!line.isEmpty()) { allReadings.add(line); } } } catch (Exception e) { e.printStackTrace(); return allReadings; } // Return the last N entries int startIndex = Math.max(0, allReadings.size() - count); return allReadings.subList(startIndex, allReadings.size()); } }
Pro tip: Instead of reading the entire file every time, use a memory cache (like a ConcurrentLinkedQueue) in the Socket server to store the latest readings. The RMI service can then query this cache directly for faster responses.
Step 3: Start the RMI Registry & Publish the Service
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class RMIMonitorServer { public static void main(String[] args) { try { // Create RMI service instance SensorMonitorService service = new SensorMonitorServiceImpl(); // Start RMI registry on default port 1099 LocateRegistry.createRegistry(1099); // Bind service to registry with a friendly name Registry registry = LocateRegistry.getRegistry(); registry.rebind("FireAlarmMonitorService", service); System.out.println("RMI monitor server started successfully"); } catch (Exception e) { e.printStackTrace(); } } }
Step 4: RMI Monitoring Client
This client connects to the RMI service and displays data to users:
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.List; public class RMIMonitorClient { public static void main(String[] args) { try { // Connect to RMI registry Registry registry = LocateRegistry.getRegistry("your-rmi-server-ip", 1099); // Look up the remote service SensorMonitorService service = (SensorMonitorService) registry.lookup("FireAlarmMonitorService"); // Call remote methods int sensorCount = service.getConnectedSensorCount(); System.out.printf("Active sensors online: %d%n", sensorCount); List<String> latestReadings = service.getLatestReadings(5); System.out.println("\nLatest 5 sensor readings:"); latestReadings.forEach(System.out::println); } catch (Exception e) { System.err.printf("Client error: %s%n", e.getMessage()); } } }
- Data Consistency: Avoid file read/write conflicts by using
FileLockor replacing the text file with an in-memory queue shared between Socket and RMI layers. - Clear Separation of Concerns: Socket handles raw data transport; RMI handles business logic queries. Don’t mix their responsibilities.
- Error Handling: Add retry logic for Socket reconnections and RMI service unavailability. Log failures to debug sensor dropouts.
- Performance:
- Use thread pooling for Socket connections to avoid resource exhaustion.
- Cache frequent RMI queries (like sensor counts) to reduce file IO.
- Replace the text file with Redis or an in-memory database for faster access.
- Add sensor heartbeats to the Socket server to track truly active devices (instead of relying on historical data).
- Implement authentication for RMI clients to prevent unauthorized access.
- Add real-time push notifications from RMI to clients using RMI callbacks.
内容的提问来源于stack exchange,提问作者kirito

