Example of creating a simple proxy server with sockets in Java

Posted by jkarr on Sun, 12 Dec 2021 12:40:49 +0100

In these examples, you can find different ways to create a simple proxy socket server. This is useful for a number of reasons:

  • Capture traffic between clients and servers.
  • Limit upload / download bandwidth to see how your website loads slow connections.
  • View the system's response when there is a problem with the network.
  • "Dynamically" modify the content of the client / server (send and receive).
  • Generate statistics about traffic.

*You can use the examples here as a basis for development. No functionality has been implemented. The following example is a proxy only. You cannot always use them as HTTP proxies.

Example 1 (multi slot proxy server) 

Use example 1 as an HTTP proxy for another HTTP proxy

Example 2 (only 1 slot at the same time)

Example 3 HTTP proxy

Example 1

import java.io.*;
import java.net.*;

/**
 *
 * @author jcgonzalez.com
 *
 */
public class ProxyMultiThread {
	public static void main(String[] args) {
		try {
			if (args.length != 3)
				throw new IllegalArgumentException("insuficient arguments");
			// and the local port that we listen for connections on
			String host = args[0];
			int remoteport = Integer.parseInt(args[1]);
			int localport = Integer.parseInt(args[2]);
			// Print a start-up message
			System.out.println("Starting proxy for " + host + ":" + remoteport + " on port " + localport);
			ServerSocket server = new ServerSocket(localport);
			while (true) {
				new ThreadProxy(server.accept(), host, remoteport);
			}
		} catch (Exception e) {
			System.err.println(e);
			System.err.println("Usage: java ProxyMultiThread " + "<host> <remoteport> <localport>");
		}
	}
}

/**
 * Handles a socket connection to the proxy server from the client and uses 2
 * threads to proxy between server and client
 *
 * @author jcgonzalez.com
 *
 */
class ThreadProxy extends Thread {
	private Socket sClient;
	private final String SERVER_URL;
	private final int SERVER_PORT;

	ThreadProxy(Socket sClient, String ServerUrl, int ServerPort) {
		this.SERVER_URL = ServerUrl;
		this.SERVER_PORT = ServerPort;
		this.sClient = sClient;
		this.start();
	}

	@Override
	public void run() {
		try {
			final byte[] request = new byte[1024];
			byte[] reply = new byte[4096];
			final InputStream inFromClient = sClient.getInputStream();
			final OutputStream outToClient = sClient.getOutputStream();
			Socket client = null, server = null;
			// connects a socket to the server
			try {
				server = new Socket(SERVER_URL, SERVER_PORT);
			} catch (IOException e) {
				PrintWriter out = new PrintWriter(new OutputStreamWriter(outToClient));
				out.flush();
				throw new RuntimeException(e);
			}
			// a new thread to manage streams from server to client (DOWNLOAD)
			final InputStream inFromServer = server.getInputStream();
			final OutputStream outToServer = server.getOutputStream();
			// a new thread for uploading to the server
			new Thread() {
				public void run() {
					int bytes_read;
					try {
						while ((bytes_read = inFromClient.read(request)) != -1) {
							outToServer.write(request, 0, bytes_read);
							outToServer.flush();
							// TODO CREATE YOUR LOGIC HERE
						}
					} catch (IOException e) {
					}
					try {
						outToServer.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}.start();
			// current thread manages streams from server to client (DOWNLOAD)
			int bytes_read;
			try {
				while ((bytes_read = inFromServer.read(reply)) != -1) {
					outToClient.write(reply, 0, bytes_read);
					outToClient.flush();
					// TODO CREATE YOUR LOGIC HERE
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (server != null)
						server.close();
					if (client != null)
						client.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			outToClient.close();
			sClient.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Compilation and use

javac ProxyMultiThread.java

java ProxyMultiThread 192.168.1.10 8080 9999

Start 192.168 on port 9999 1.10:8180 agent

(traffic is now redirected from localhost 9999 to 192.168.1.10 through the proxy. Remember, Web browsers may not always be valid due to HTTP host tags, referrals, javascript redirection, etc.

 

Use example 1 as an HTTP proxy for another HTTP proxy

If your HTTP proxy is myproxy.test.net on port 380 and you want to use java as the proxy before java arrives at the proxy, run it as follows.

java ProxyMultiThread myproxy.test.net 80 9999

Now adjust the browser configuration to use the proxy on the local host 9999

In Firefox:

*Now, all your traffic should go to example 1 first and then to your agent.

Example 2

// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples
import java.io.*;
import java.net.*;

/**
 * This class implements a simple single-threaded proxy server.
 **/
public class SimpleProxyServer {
	/** The main method parses arguments and passes them to runServer */
	public static void main(String[] args) throws IOException {
		try {
			// Check the number of arguments
			if (args.length != 3)
				throw new IllegalArgumentException("Wrong number of arguments.");
			// Get the command-line arguments: the host and port we are proxy for
			// and the local port that we listen for connections on
			String host = args[0];
			int remoteport = Integer.parseInt(args[1]);
			int localport = Integer.parseInt(args[2]);
			// Print a start-up message
			System.out.println("Starting proxy for " + host + ":" + remoteport + " on port " + localport);
			// And start running the server
			runServer(host, remoteport, localport); // never returns
		} catch (Exception e) {
			System.err.println(e);
			System.err.println("Usage: java SimpleProxyServer " + "<host> <remoteport> <localport>");
		}
	}

	/**
	 * This method runs a single-threaded proxy server for host:remoteport on the
	 * specified local port. It never returns.
	 **/
	public static void runServer(String host, int remoteport, int localport) throws IOException {
		// Create a ServerSocket to listen for connections with
		ServerSocket ss = new ServerSocket(localport);
		// Create buffers for client-to-server and server-to-client communication.
		// We make one final so it can be used in an anonymous class below.
		// Note the assumptions about the volume of traffic in each direction...
		final byte[] request = new byte[1024];
		byte[] reply = new byte[4096];
		// This is a server that never returns, so enter an infinite loop.
		while (true) {
			// Variables to hold the sockets to the client and to the server.
			Socket client = null, server = null;
			try {
				// Wait for a connection on the local port
				client = ss.accept();
				// Get client streams. Make them final so they can
				// be used in the anonymous thread below.
				final InputStream from_client = client.getInputStream();
				final OutputStream to_client = client.getOutputStream();
				// Make a connection to the real server
				// If we cannot connect to the server, send an error to the
				// client, disconnect, then continue waiting for another connection.
				try {
					server = new Socket(host, remoteport);
				} catch (IOException e) {
					PrintWriter out = new PrintWriter(new OutputStreamWriter(to_client));
					out.println("Proxy server cannot connect to " + host + ":" + remoteport + ":\n" + e);
					out.flush();
					client.close();
					continue;
				}
				// Get server streams.
				final InputStream from_server = server.getInputStream();
				final OutputStream to_server = server.getOutputStream();
				// Make a thread to read the client's requests and pass them to the
				// server. We have to use a separate thread because requests and
				// responses may be asynchronous.
				new Thread() {
					public void run() {
						int bytes_read;
						try {
							while ((bytes_read = from_client.read(request)) != -1) {
								to_server.write(request, 0, bytes_read);
								System.out
										.println(bytes_read + "to_server--->" + new String(request, "UTF-8") + "<---");
								to_server.flush();
							}
						} catch (IOException e) {
						}
						// the client closed the connection to us, so close our
						// connection to the server. This will also cause the
						// server-to-client loop in the main thread exit.
						try {
							to_server.close();
						} catch (IOException e) {
						}
					}
				}.start();
				// Meanwhile, in the main thread, read the server's responses
				// and pass them back to the client. This will be done in
				// parallel with the client-to-server request thread above.
				int bytes_read;
				try {
					while ((bytes_read = from_server.read(reply)) != -1) {
						try {
							Thread.sleep(1);
							System.out.println(bytes_read + "to_client--->" + new String(request, "UTF-8") + "<---");
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						to_client.write(reply, 0, bytes_read);
						to_client.flush();
					}
				} catch (IOException e) {
				}
				// The server closed its connection to us, so close our
				// connection to our client. This will make the other thread exit.
				to_client.close();
			} catch (IOException e) {
				System.err.println(e);
			}
			// Close the sockets no matter what happens each time through the loop.
			finally {
				try {
					if (server != null)
						server.close();
					if (client != null)
						client.close();
				} catch (IOException e) {
				}
			}
		} // while(true)
	}
}

Example 3 HTTP proxy

I use Benjamin Kohl & Artem Melnik's HTTP Java Proxy Download here Or go to the original site here.

note

  • You can use Thread.sleep to limit bandwidth, throw random exceptions to disrupt the network, modify content, and so on.

Topics: network server p2p