使用NIO实现的异步简单HTTP代理服务器,不支持HTTPS代理。
文件名:Main.java
package jHttpProxy; import java.io.IOException; import java.net.*; import java.nio.channels.*; import java.util.Iterator; /* * http代理服务器 * @author chenlei1998 * */ public class Main { //监听80端口 private final static int port = 8888; //监听所有ip private final static String host = "0.0.0.0"; private final static int backlog = 1024; public static void main(String[] args) throws IOException { ServerSocketChannel aServerSocketChannel = ServerSocketChannel.open(); aServerSocketChannel.socket().setReuseAddress(true); aServerSocketChannel.socket().bind(new InetSocketAddress(host, port), backlog); //设置为非阻塞 aServerSocketChannel.configureBlocking(false); Selector aSelector = Selector.open(); aServerSocketChannel.register(aSelector, SelectionKey.OP_ACCEPT); System.out.println("服务器正在监听中"); //事件循环 while (true) { if (aSelector.select() > 0) { Iterator<SelectionKey> aIterator = aSelector.selectedKeys().iterator(); while (aIterator.hasNext()) { SelectionKey aKey = null; try { aKey = aIterator.next(); aIterator.remove(); HttpRequestForwarder aHttpRequestForwarder = null; SocketChannel aSocketChannel = null; if (aKey.attachment() != null) { aHttpRequestForwarder = (HttpRequestForwarder)aKey.attachment(); } if (aKey.isAcceptable()) { aSocketChannel = aServerSocketChannel.accept(); aSocketChannel.configureBlocking(false); aSocketChannel.register(aSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, new HttpRequestForwarder(aSelector, aSocketChannel)); } else if (aKey.isReadable()) { aSocketChannel = (SocketChannel)aKey.channel(); aHttpRequestForwarder.onRead(aSocketChannel); } else if (aKey.isWritable()) { aSocketChannel = (SocketChannel)aKey.channel(); aHttpRequestForwarder.onWrite(aSocketChannel); } else if (aKey.isConnectable()) { aSocketChannel = (SocketChannel)aKey.channel(); if (aSocketChannel.isConnectionPending()) { aSocketChannel.finishConnect(); } aKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); } } catch (IOException e) { e.printStackTrace(); } catch (CancelledKeyException e) { e.printStackTrace(); } } } } } }文件名:HttpRequestForwarder.java
package jHttpProxy; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress;import java.net.SocketOption; import java.net.URL; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.LinkedList; import java.util.Scanner; /* * 异步转发HTTP请求 * @author chenlei1998 * */ public class HttpRequestForwarder { private SocketChannel first; private SocketChannel second; private SocketAddress remoteAddress; private Selector selector; private LinkedList<ByteBuffer> firstBufferList; private LinkedList<ByteBuffer> secondBufferList; private HttpRequestHeader httpRequestHeader; public HttpRequestForwarder(Selector aSelector, SocketChannel aFirst) throws IOException { first = aFirst; selector = aSelector; second = SocketChannel.open(); second.configureBlocking(false); second.socket().setTcpNoDelay(true); httpRequestHeader = null; remoteAddress = null; firstBufferList = new LinkedList<ByteBuffer>(); secondBufferList = new LinkedList<ByteBuffer>(); } /* * 响应channel可读事件 * */ public void onRead(SocketChannel aSocketChannel) { ByteBuffer buffer = ByteBuffer.allocate(4096); buffer.clear(); try { if (first.equals(aSocketChannel)) { int len = first.read(buffer); if (len < 0) { throw new IOException(); } buffer.flip(); if (httpRequestHeader == null) { httpRequestHeader = new HttpRequestHeader(); if (!httpRequestHeader.parse(buffer)) { throw new IOException(); } else { //组装HTTP请求头 String host = httpRequestHeader.getHeaders().get("host"); URL url = new URL(httpRequestHeader.getPath()); int port = 80; if (host.split(":").length == 2) { port = Integer.parseInt(host.split(":")[1]); } String strBuffer = new String(buffer.array()); StringBuilder headers = new StringBuilder(); headers.append(httpRequestHeader.getMethod()); headers.append(" "); headers.append(url.getPath()); if (url.getQuery() != null) { headers.append("?"); headers.append(url.getQuery()); } headers.append(" "); headers.append(httpRequestHeader.getVersion()); strBuffer = strBuffer.replaceFirst("Connection: .*\r\n", "Connection: close\r\n"); headers.append(strBuffer.substring(strBuffer.indexOf("\r\n"))); buffer = ByteBuffer.wrap(headers.toString().getBytes()); remoteAddress = new InetSocketAddress(host, port); second.register(selector, SelectionKey.OP_CONNECT, this); second.connect(remoteAddress); } } firstBufferList.add(buffer); } else if (second.equals(aSocketChannel)) { int len = second.read(buffer); if (len < 0) { throw new IOException(); } buffer.flip(); secondBufferList.add(buffer); } } catch (IOException e) { if (first != null) { try { first.close(); first = null; } catch (IOException e1) { } } if (second != null) { try { second.close(); second = null; } catch (IOException e1) { } } } } /* * 响应channel可写事件 * */ public void onWrite(SocketChannel aSocketChannel) { try { if (first.equals(aSocketChannel) && !secondBufferList.isEmpty()) { while (!secondBufferList.isEmpty()) { ByteBuffer buffer = secondBufferList.getFirst(); while (buffer.remaining() > 0) { first.write(buffer); } secondBufferList.removeFirst(); } } else if (second.equals(aSocketChannel) && !firstBufferList.isEmpty()) { while (!firstBufferList.isEmpty()) { ByteBuffer buffer = firstBufferList.getFirst(); System.out.println(new String(buffer.array())); while (buffer.remaining() > 0) { second.write(buffer); } firstBufferList.removeFirst(); } } } catch (IOException e) { if (first != null) { try { first.close(); first = null; } catch (IOException e1) { } } if (second != null) { try { second.close(); second = null; } catch (IOException e1) { } } } } }文件名: HttpRequestHeader.java
package jHttpProxy; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.util.HashMap; /* * 解析HTTP协议请求头 * @author chenlei1998 * */ public class HttpRequestHeader { //请求方法 private String method; //请求路径 private String path; //HTTP协议版本 private String version; //Header private HashMap<String, String> headers; private final static int MAXLINE = 8192; public HttpRequestHeader() { method = null; path = null; version = null; headers = new HashMap<String, String>(); } public String getPath() { return path; } public String getMethod() { return method; } public HashMap<String, String> getHeaders() { return headers; } public String getVersion() { return version; } public boolean parse(String stringBuffer) throws IOException { return parse(stringBuffer.getBytes()); } public boolean parse(ByteBuffer byteBuffer) throws IOException { return parse(byteBuffer.array()); } public boolean parse(byte[] byteBuffer) throws IOException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteBuffer); InputStreamReader inputStreamReader = new InputStreamReader(byteArrayInputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); while (bufferedReader.ready()) { String line = bufferedReader.readLine(); if (line.length() >= MAXLINE) { return false; } if (method == null) { String[] info = line.split(" "); if (info.length != 3) { return false; } method = info[0]; path = info[1]; version = info[2]; } else if (line.indexOf(":") > 0) { String fieldName = line.substring(0, line.indexOf(":")); String fieldValue = line.substring(line.indexOf(":") + 1).trim(); headers.put(fieldName.toLowerCase(), fieldValue); } else if (line.isEmpty()) { break; } } return (method != null && path != null && version != null); } }