Skip to content

Commit 3cddd8f

Browse files
committed
feat(udp): add DatagramClient and Datagram Server with robust example and full design notes
What - Added two UDP example programs under package `imrovedversion`: 1. `DatagramClient` — a simple, single-shot UDP client that sends a text message ("Hello Server") to localhost:2000, waits for a response, prints it, and then closes the socket. 2. `Server` — a long-running UDP server that listens on port 2000, receives datagrams, reverses the received text, and replies to the sender with the reversed string. Why - Provide a minimal, real-world UDP example to demonstrate: - DatagramSocket/DatagramPacket usage. - Blocking receive semantics for UDP. - Bi-directional request/response pattern over UDP. - Practical considerations (buffer sizing, trimming packet data, resource closing). - Helpful for networking lessons, demos, and quick experiments with unreliable, connectionless protocols. How (overview) - Client: - Creates an unbound DatagramSocket (OS assigns an ephemeral port). - Encodes outgoing message to bytes with default platform charset. - Sends DatagramPacket to server address `localhost:2000`. - Allocates a fixed-size receive buffer (1024 bytes) and blocks on `receive()` until a response arrives. - Converts received bytes into a String using `new String(byte[], 0, length)` to avoid trailing zeros. - Closes socket. - Server: - Opens a DatagramSocket bound to port 2000. - Runs an infinite loop calling `receive()` on a reusable buffer (1024 bytes). - Builds a `String` from the received packet using the packet length (avoids junk bytes). - Applies a simple processing step (reverse string). - Sends back the processed result to the sender's address and port from the received packet. - Continues listening (no explicit shutdown in current code). Detailed implementation notes / rationale - Buffer sizing: - Both client and server use a 1024-byte receive buffer. This is a safe default for small text messages, but for larger payloads you should increase the buffer or implement fragmentation and reassembly at the application level. - Trimming / packet length: - Convert received bytes with `new String(packet.getData(), 0, packet.getLength())` — this is essential because `getData()` returns the entire backing array which may be larger than the actual data. - Character encoding: - Current code uses platform default encoding (`getBytes()` / `new String(byte[])`). For determinism and portability, prefer specifying `StandardCharsets.UTF_8` (e.g., `msg.getBytes(StandardCharsets.UTF_8)` and `new String(..., StandardCharsets.UTF_8)`). - Blocking semantics & timeouts: - `ds.receive()` is blocking. If you expect long waits or want to terminate gracefully, consider `ds.setSoTimeout(timeoutMillis)` and handle `SocketTimeoutException`. - Concurrency: - The server is single-threaded and sequentially handles requests. For higher throughput, consider dispatching processing to a worker thread pool (be mindful of reply ordering and packet sizes). - Resource management: - Client closes its socket when done. Server currently runs forever and does not call `close()` — add shutdown handling if embedding in a larger application (e.g., hook into JVM shutdown or use ExecutorService with an interruptible loop). - Error handling: - Current methods `throws Exception` (main) for brevity. In production code, catch and log `IOException`, `SocketException` and ensure sockets are closed in `finally` blocks or try-with-resources where applicable. - Port / address configuration: - Port and host are hard-coded for clarity; make these configurable (command-line args, environment variables, or config file) for flexible usage. - Packet size & message boundaries: - UDP preserves message boundaries — one `send()` corresponds to one `receive()`. Server uses that to reverse exactly the received message. - Security considerations: - UDP is unauthenticated and spoofable. Do not accept untrusted data without validation. For real deployments, consider applying authentication/encryption (e.g., Datagram TLS-like protocols or application-level signatures). - Beware of amplification / reflection attacks when building public UDP services. - Network reliability: - UDP is unreliable (packets can be lost, duplicated, reordered). For guaranteed delivery or ordered streams, use TCP or add retransmission/ACK logic at the application layer. How to run (example) 1. Start the server (in one terminal / IDE): - `java imrovedversion.Server` - Expected output: ``` Server: Listening on port 2000... ``` 2. Start the client (in another terminal / IDE): - `java imrovedversion.DatagramClient` - Expected output (client): ``` Client: Message sent to Server. Client: Response from Server -> <reversed "Hello Server"> ``` - Expected output (server console when processing): ``` Server: Received -> Hello Server Server: Sent back reversed message. ``` Example interaction - Client sends: `Hello Server` - Server receives: `Hello Server` - Server replies: `revreS olleH` (the reversed string) - Client prints the reply. Testing notes - Localhost tests are fine for learning. To test across machines, ensure: - Firewalls allow inbound UDP on the chosen port. - Use server machine IP instead of `localhost`. - Test with different payload sizes to validate buffer sizing. - Test packet loss scenarios with network tools (e.g., `tc` on Linux) to observe and design for loss/retransmission if needed. Potential improvements / roadmap - Add charset explicitness: use `StandardCharsets.UTF_8`. - Add CLI flags: host, port, message, buffer-size, timeout. - Server improvements: - Add graceful shutdown via shutdown hook. - Use ExecutorService to offload processing to worker threads and improve throughput. - Add request-id correlation if client sends multiple requests and expects matched replies. - Reliability: - Implement simple ACK/retry or sequence numbers if reliable delivery is required. - Metrics & logging: - Integrate a logging framework (SLF4J/Logback) and add basic metrics (requests/sec, bytes processed, errors). - Security: - Validate input size and content to avoid resource exhaustion. - If appropriate, layer DTLS or use encrypted channels. Real-world use cases - Low-latency, fire-and-forget telemetry (sensor data, syslog, metrics like StatsD). - Simple UDP-based RPC for lightweight services (e.g., game servers exchanging quick state updates). - Discovery protocols (e.g., service discovery broadcast/announce). - Learning and teaching networking primitives in Java. Compatibility & portability - The code uses only JDK standard classes (`java.net.DatagramSocket`, `DatagramPacket`, `InetAddress`) — compatible with any Java SE runtime (8+). - Recommend using UTF-8 for cross-platform string encoding. Notes & cautions - UDP is not connection-oriented — no `connect()` call is used; server replies to the packet's source address & port. - There is no built-in backpressure: rapid sends can overflow receiver buffers or cause packet loss. - For production-grade systems, choose TCP, QUIC, or add application-level reliability depending on requirements. Signed-off-by: https://github.com/Someshdiwan <[email protected]>
1 parent a75cfe4 commit 3cddd8f

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package imrovedversion;
1+
package ImprovedVersion;
22

33
import java.net.*;
44

@@ -26,4 +26,4 @@ public static void main(String[] args) throws Exception {
2626

2727
ds.close();
2828
}
29-
}
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
1. DatagramSocket:
2+
- UDP protocol ke liye use hota hai (connectionless).
3+
- Client side: `new DatagramSocket()` → system automatic free port allocate karta hai.
4+
- Server side: `new DatagramSocket(2000)` → explicitly port bind kiya jata hai.
5+
6+
2. DatagramPacket:
7+
- Ek packet = data + destination address + port.
8+
- Client `send()` karta hai → packet server ke port tak pahunchta hai.
9+
- Server `receive()` karta hai → blocking call (jab tak data nahi aata, rukta hai).
10+
11+
3. Client Flow:
12+
- Message `"Hello Server"` ko byte[] me convert kiya.
13+
- `DatagramPacket` banaya with `serverAddress = localhost, port=2000`.
14+
- `ds.send(dp)` → message server tak chala gaya.
15+
- Fir ek naya empty packet bana → server ka response receive kiya.
16+
- `response.getData()` se byte[] nikaal kar string me convert kiya.
17+
18+
4. Server Flow:
19+
- Port `2000` pe continuously listen karta hai.
20+
- Har aane wale packet ko `dp.getData()` se String banata hai.
21+
- Message ko reverse karta hai → `"Hello Server"` → `"revreS olleH"`.
22+
- Response packet bana ke wapas client ke address + port pe send karta hai.
23+
24+
5. Output Pattern (Example):
25+
26+
Server:
27+
Server: Listening on port 2000…
28+
Server: Received -> Hello Server
29+
Server: Sent back reversed message.
30+
31+
Client:
32+
Client: Message sent to Server.
33+
Client: Response from Server -> revreS olleH
34+
35+
✔ UDP = fast, lightweight, but connectionless (no guarantee).
36+
✔ DatagramSocket (server bind to port, client no bind needed).
37+
✔ DatagramPacket = actual container of data.
38+
✔ Example: client sends message → server reverses → sends back.
39+
✔ Real-world: chat apps, multiplayer games, DNS, where speed > reliability.

Section27NetworkProgramming/DataGramReverseEchoServer/src/imrovedversion/Server.java renamed to Section27NetworkProgramming/DataGramReverseEchoServer/src/ImprovedVersion/Server.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
package imrovedversion;
1+
package ImprovedVersion;
22

33
import java.net.*;
44

55
public class Server {
66
public static void main(String[] args) throws Exception {
7-
DatagramSocket ds = new DatagramSocket(2000); // Server listening on port 2000
7+
DatagramSocket ds = new DatagramSocket(2000);
8+
// Server listening on port 2000
9+
810
System.out.println("Server: Listening on port 2000...");
911

1012
byte[] buffer = new byte[1024];
1113

1214
while (true) { // Continuous listening mode
1315
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
14-
ds.receive(dp); // Receiving message
16+
ds.receive(dp); // Receiving a message.
1517

16-
String receivedMsg = new String(dp.getData(), 0, dp.getLength()); // Trim excess bytes
18+
String receivedMsg = new String(dp.getData(), 0, dp.getLength()); // Trim excess bytes.
1719
System.out.println("Server: Received -> " + receivedMsg);
1820

19-
// Reverse the received message
21+
// Reverse the received message.
2022
String reversedMsg = new StringBuilder(receivedMsg).reverse().toString();
2123

22-
// Send response back to client
24+
// Send a response back to a client.
2325
DatagramPacket response = new DatagramPacket(
2426
reversedMsg.getBytes(), reversedMsg.length(),
2527
dp.getAddress(), dp.getPort()

0 commit comments

Comments
 (0)