Java provides robust networking capabilities for building distributed applications. This guide covers everything from basic socket programming to modern HTTP clients and NIO.
Key areas covered:
public class TCPServer {
private final ServerSocket serverSocket;
private final ExecutorService executor;
public TCPServer(int port) throws IOException {
this.serverSocket = new ServerSocket(port);
this.executor = Executors.newCachedThreadPool();
}
public void start() {
try {
while (true) {
Socket clientSocket = serverSocket.accept();
executor.execute(() -> handleClient(clientSocket));
}
} catch (IOException e) {
log.error("Server error", e);
}
}
private void handleClient(Socket clientSocket) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true)) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println("Server received: " + inputLine);
}
} catch (IOException e) {
log.error("Client handling error", e);
}
}
public void stop() {
try {
executor.shutdown();
serverSocket.close();
} catch (IOException e) {
log.error("Error stopping server", e);
}
}
}
public class TCPClient {
private final String host;
private final int port;
public TCPClient(String host, int port) {
this.host = host;
this.port = port;
}
public void sendMessage(String message) {
try (Socket socket = new Socket(host, port);
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()))) {
out.println(message);
String response = in.readLine();
log.info("Server response: {}", response);
} catch (IOException e) {
log.error("Error communicating with server", e);
}
}
}
public class HTTPClientExample {
private final HttpClient client;
public HTTPClientExample() {
this.client = HttpClient.newBuilder()
.version(Version.HTTP_2)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.build();
}
public String sendGetRequest(String url)
throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofMinutes(1))
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse response =
client.send(request,
HttpResponse.BodyHandlers.ofString());
return response.body();
}
public String sendPostRequest(String url,
String jsonBody) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofMinutes(1))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
jsonBody))
.build();
HttpResponse response =
client.send(request,
HttpResponse.BodyHandlers.ofString());
return response.body();
}
public void sendAsyncRequest(String url) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
client.sendAsync(request,
HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
}
}
public class NIOServer {
private final ServerSocketChannel serverChannel;
private final Selector selector;
public NIOServer(int port) throws IOException {
serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(port));
serverChannel.configureBlocking(false);
selector = Selector.open();
serverChannel.register(selector,
SelectionKey.OP_ACCEPT);
}
public void start() throws IOException {
while (true) {
selector.select();
Set selectedKeys =
selector.selectedKeys();
Iterator iter =
selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
handleAccept(serverChannel, key);
}
if (key.isReadable()) {
handleRead(key);
}
iter.remove();
}
}
}
private void handleAccept(ServerSocketChannel myServer,
SelectionKey key) throws IOException {
SocketChannel client = myServer.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
private void handleRead(SelectionKey key)
throws IOException {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
if (bytesRead == -1) {
client.close();
return;
}
buffer.flip();
client.write(buffer);
buffer.clear();
}
}
public class SecureServer {
private final SSLServerSocket serverSocket;
public SecureServer(int port) throws Exception {
SSLServerSocketFactory factory =
(SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket)
factory.createServerSocket(port);
// Configure cipher suites
String[] enabledCipherSuites =
serverSocket.getSupportedCipherSuites();
serverSocket.setEnabledCipherSuites(
enabledCipherSuites);
}
public void start() {
try {
while (true) {
SSLSocket client = (SSLSocket)
serverSocket.accept();
handleSecureClient(client);
}
} catch (IOException e) {
log.error("Secure server error", e);
}
}
private void handleSecureClient(SSLSocket client) {
try {
// Handle secure communication
SSLSession session = client.getSession();
log.info("Secure connection established: {}",
session.getCipherSuite());
} catch (Exception e) {
log.error("Secure client handling error", e);
}
}
}
Java provides robust networking capabilities for building distributed applications. By following the patterns and practices outlined in this guide, you can effectively implement network programming solutions in your Java applications.
Remember to focus on security, proper resource management, and error handling for reliable network programming.