-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMathServer.java
More file actions
114 lines (101 loc) · 4.96 KB
/
Copy pathMathServer.java
File metadata and controls
114 lines (101 loc) · 4.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import java.io.*;
import java.net.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.LinkedBlockingQueue;
// Main server class - listens for incoming client connections on specified port
public class MathServer {
// Port number clients must connect to
private static final int PORT = 6789;
// Shared queue ensures all client requests are processed in order of arrival
public static final LinkedBlockingQueue<Runnable> requestQueue = new LinkedBlockingQueue<>();
public static void main(String[] args) {
try (ServerSocket welcomeSocket = new ServerSocket(PORT)) {
System.out.println("Math Server is UP and running on port " + PORT);
// Single worker thread processes one request at a time to maintain order
Thread worker = new Thread(() -> {
while (true) {
try { requestQueue.take().run(); }
catch (InterruptedException e) { break; }
}
});
worker.setDaemon(true);
worker.start();
// Continuously accept new client connections and spawn a handler thread for each
while (true) {
Socket connectionSocket = welcomeSocket.accept();
new ClientHandler(connectionSocket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Handles each client in its own thread to allow simultaneous connections
class ClientHandler extends Thread {
private Socket socket;
private String clientName;
private LocalDateTime startTime;
public ClientHandler(Socket socket) {
this.socket = socket;
this.startTime = LocalDateTime.now(); // Record connection time to calculate session duration
}
public void run() {
try (BufferedReader inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream())) {
String clientSentence;
while ((clientSentence = inFromClient.readLine()) != null) {
String[] parts = clientSentence.split(MathProtocol.SEPARATOR);
String command = parts[0];
if (command.equals(MathProtocol.CONNECT)) {
this.clientName = parts[1];
System.out.println("[" + startTime + "] Client Attached: " + clientName);
outToClient.writeBytes(MathProtocol.ACK + "\n");
}
else if (command.equals(MathProtocol.MATH_REQ)) {
final String[] p = parts;
final String name = clientName;
// Add math request to shared queue for ordered processing
MathServer.requestQueue.put(() -> {
String op = p[1];
int n1 = Integer.parseInt(p[2]);
int n2 = Integer.parseInt(p[3]);
// Check for division by zero before calculating
if (op.equalsIgnoreCase("DIV") && n2 == 0) {
System.out.println("[" + LocalDateTime.now() + "] ERROR | " + name + " | DIV by zero");
try { outToClient.writeBytes(MathProtocol.ERROR + MathProtocol.SEPARATOR + "Division by zero\n"); }
catch (IOException e) { e.printStackTrace(); }
return;
}
int result = calculate(op, n1, n2);
System.out.println("[" + LocalDateTime.now() + "] REQUEST | " + name + " | " + op + " | " + n1 + " | " + n2);
try { outToClient.writeBytes("RESULT" + MathProtocol.SEPARATOR + result + "\n"); }
catch (IOException e) { e.printStackTrace(); }
});
}
else if (command.equals(MathProtocol.CLOSE)) {
break;
}
}
} catch (IOException e) {
System.out.println("Error handling client " + clientName);
} catch (InterruptedException e) {
System.out.println("Request queue interrupted for client " + clientName);
} finally {
// Log session duration and close socket when client disconnects
long duration = Duration.between(startTime, LocalDateTime.now()).getSeconds();
System.out.println("Client " + clientName + " disconnected. Session: " + duration + "s");
try { socket.close(); } catch (IOException e) { e.printStackTrace(); }
}
}
// Perform math calculation based on operator string
private int calculate(String op, int a, int b) {
switch (op.toUpperCase()) {
case "ADD": return a + b;
case "SUB": return a - b;
case "MUL": return a * b;
case "DIV": return (b != 0) ? a / b : 0;
default: return 0;
}
}
}