Core Connection Mechanisms
Java provides robust support for creating networked aplications through the java.net package. At its foundation, a socket acts as an endpoint for sending or receiving data between machines across a network using the Transmission Control Protocol (TCP). Below is an example demonstrating how to establish a basic text-based communication channel.
TCP Listening Service
public class ChatProtocolHandler { public static void main(String[] args) { int port = 9001; try (ServerSocket listener = new ServerSocket(port)) { System.out.println("Service listening on port " + port);
Socket connection = listener.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
PrintWriter writer = new PrintWriter(connection.getOutputStream(), true);
String message = reader.readLine();
System.out.println("Received: " + message);
writer.println("Acknowledged");
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
</div>### TCP Initiator
<div>```
import java.io.*;
import java.net.*;
public class ConnectionInitiator {
public static void main(String[] args) throws Exception {
try (Socket target = new Socket("localhost", 9001)) {
PrintWriter out = new PrintWriter(target.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(target.getInputStream(), StandardCharsets.UTF_8));
out.println("Hello World");
String response = in.readLine();
System.out.println("Reply: " + response);
}
}
}
When transferring binary data, buffering is critical to ensure efficient throughput. The server below supports concurrent clients by spawning a new thread for each connection, preventing bottlenecks.
Download & Receive Logic
public class AsyncFileReceiver { public static void main(String[] args) throws IOException { int acceptPort = 9002; try (ServerSocket acceptor = new ServerSocket(acceptPort)) { while (true) { Socket currentConn = acceptor.accept(); new Thread(() -> { try (InputStream in = currentConn.getInputStream(); OutputStream out = currentConn.getOutputStream(); FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".bin")) {
byte[] buf = new byte[4096];
int readBytes;
while ((readBytes = in.read(buf)) != -1) {
fos.write(buf, 0, readBytes);
}
out.write("Sync complete".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
currentConn.close();
}
}).start();
}
}
}
}
</div>### Data Uploader
<div>```
import java.io.*;
import java.net.*;
import java.nio.file.Paths;
public class BinarySender {
public static void main(String[] args) throws Exception {
Path source = Paths.get("./data.bin");
Socket link = new Socket("127.0.0.1", 9002);
try (InputStream fis = Files.newInputStream(source);
OutputStream os = link.getOutputStream()) {
byte[] chunk = new byte[4096];
int count;
while ((count = fis.read(chunk)) != -1) {
os.write(chunk, 0, count);
}
link.shutdownOutput(); // Signal end of transmission
InputStream is = link.getInputStream();
byte[] ackBuf = new byte[1024];
int ackLen = is.read(ackBuf);
System.out.println("Server Status: " + new String(ackBuf, 0, ackLen));
} finally {
link.close();
}
}
}
To understand how web servers process requests, we can create a minimal HTTP handler. This implemantation parses a raw request string and serves a static resource file, mimicking standard GET operations.
public class MiniWebHost { public static void main(String[] args) throws IOException { ServerSocket wsSocket = new ServerSocket(8080);
while (true) {
Socket clientSocket = wsSocket.accept();
new Thread(() -> {
try {
BufferedReader reqReader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String requestLine = reqReader.readLine();
// Extract path from "GET /index.html HTTP/1.1"
String path = requestLine.split("\\s+")[1].substring(1);
FileInputStream fs = new FileInputStream(path);
OutputStream netStream = clientSocket.getOutputStream();
netStream.write("HTTP/1.1 200 OK\r\n".getBytes());
netStream.write("Content-Type: text/html\r\n\r\n".getBytes());
byte[] pageBuffer = new byte[2048];
int size;
while ((size = fs.read(pageBuffer)) > 0) {
netStream.write(pageBuffer, 0, size);
}
fs.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
</div>### Implementation Notes
A key aspect of raw socket programming is understanding blocking behavior. If the input stream attempts to read data that has not been sent yet, the thread executing the read operation will pause until the data arrives. Proper synchronization and termination signals (like `shutdownOutput()`) are essential to prevent infinite waits during testing.