使用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);
}
}