Creating a proxy server using ProxySelector
and Socket
in Java involves a few steps. ProxySelector
is used to determine which proxy to use for connections, while Socket
facilitates communication with the client and/or the target server behind the proxy.
Here’s a step-by-step guide:
1. Setup ProxySelector
A custom ProxySelector
can be created to define the proxy behavior. The select(URI uri)
method of ProxySelector
decides which proxy should be used for a given URI.
2. Create a Server Socket
A ServerSocket
will listen for incoming client requests. Once a client is connected, communication between client and the target server through the proxy is handled via sockets.
3. Communicate between the Client and Remote Server
You’ll use a Socket
to connect to the remote server via the proxy. The data from the client is forwarded to the remote server, and the response from the remote server is sent back to the client.
Example Code:
package org.kodejava.net;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
public class ProxyServerExample {
public static void main(String[] args) {
int localPort = 8888; // The port your proxy server will listen on
try (ServerSocket serverSocket = new ServerSocket(localPort)) {
System.out.println("Proxy server is running on port: " + localPort);
// Custom ProxySelector
ProxySelector.setDefault(new CustomProxySelector());
while (true) {
// Accept incoming client connections
Socket clientSocket = serverSocket.accept();
System.out.println("Accepted connection from: " + clientSocket.getRemoteSocketAddress());
// Handle the connection in a separate thread
new Thread(new ProxyHandler(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// Custom ProxySelector class
static class CustomProxySelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
List<Proxy> proxies = new ArrayList<>();
// Specify your proxy details here
proxies.add(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080)));
return proxies;
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
System.err.printf("Failed to connect to proxy: %s%n", sa);
}
}
// ProxyHandler to manage client-server communication
static class ProxyHandler implements Runnable {
private final Socket clientSocket;
public ProxyHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
try (InputStream clientIn = clientSocket.getInputStream();
OutputStream clientOut = clientSocket.getOutputStream()) {
BufferedReader clientReader = new BufferedReader(new InputStreamReader(clientIn));
OutputStreamWriter clientWriter = new OutputStreamWriter(clientOut);
// Read the first line from the client (usually HTTP request line)
String clientRequestLine = clientReader.readLine();
System.out.println("Client Request: " + clientRequestLine);
if (clientRequestLine != null) {
// Extract the target host and port from the client request
String[] requestParts = clientRequestLine.split(" ");
String targetHost = new URI(requestParts[1]).getHost();
int targetPort = new URI(requestParts[1]).getPort() != -1 ? new URI(requestParts[1]).getPort() : 80;
// Connect to the target server through the proxy
List<Proxy> proxies = ProxySelector.getDefault().select(new URI(requestParts[1]));
Proxy proxy = proxies.isEmpty() ? Proxy.NO_PROXY : proxies.get(0);
System.out.println("Connecting to: " + targetHost + ":" + targetPort + " via " + proxy);
// Connect to the target server
Socket serverSocket;
if (proxy.type().equals(Proxy.Type.DIRECT)) {
// A direct connection to the target host
serverSocket = new Socket(targetHost, targetPort);
} else if (proxy.type().equals(Proxy.Type.HTTP)) {
// Connect through an HTTP proxy
InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
serverSocket = new Socket(proxyAddress.getHostName(), proxyAddress.getPort());
} else {
throw new IOException("Unsupported proxy type: " + proxy.type());
}
// Forward client's request to the server
try (OutputStream serverOut = serverSocket.getOutputStream();
InputStream serverIn = serverSocket.getInputStream()) {
serverOut.write((clientRequestLine + "\r\n").getBytes());
serverOut.flush();
// Forward other client headers to the server
String line;
while ((line = clientReader.readLine()) != null && !line.isEmpty()) {
serverOut.write((line + "\r\n").getBytes());
serverOut.flush();
}
serverOut.write("\r\n".getBytes());
serverOut.flush();
// Read server response and forward to the client
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = serverIn.read(buffer)) != -1) {
clientOut.write(buffer, 0, bytesRead);
clientOut.flush();
}
}
serverSocket.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
How It Works:
- ProxySelector:
CustomProxySelector
determines which proxy to use for a particular URI.- Modify the proxy host and port in
CustomProxySelector
to suit your requirements.
- Proxy Server:
- The proxy server listens for incoming client requests on a specified port using
ServerSocket
.
- The proxy server listens for incoming client requests on a specified port using
- Handling Requests:
- A new thread is started for each incoming client connection to handle the client’s request and forward it to the target server via the proxy.
- Forwarding Traffic:
ProxyHandler
reads data from the client, connects to the target server through the proxy (if required), forwards the data, and sends the response back to the client.
Key Considerations:
- Validate input to ensure the proxy server cannot be exploited.
- Add proper error handling/logging.
- Consider using a library like Netty or Jetty for production-grade performance.
- This example is a basic proxy that works for simple HTTP requests. For HTTPS, consider HTTP CONNECT tunneling.
This structure forms a good starting point for a custom proxy server in Java!
- How do I secure servlets with declarative security in web.xml - April 24, 2025
- How do I handle file uploads using Jakarta Servlet 6.0+? - April 23, 2025
- How do I serve static files through a Jakarta Servlet? - April 23, 2025