簡單的HTTP代理服務器實現

基於Java完成。有詳細註釋。

package proxy2;

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

public class MyHttpProxy extends Thread {
	static public int CONNECT_RETRIES = 5; // 嘗試與目標主機連接次數
	static public int CONNECT_PAUSE = 5; // 每次建立連接的間隔時間
	static public int TIMEOUT = 50; // 每次嘗試連接的最大時間
	static public int BUFSIZ = 1024; // 緩衝區最大字節數
	static public boolean logging = false; // 是否記錄日誌
	static public OutputStream log_S = null; // 日誌輸出流
	static public OutputStream log_C = null; // 日誌輸出流
	static public String LOGFILENAME_S = "log_S.txt";
	static public String LOGFILENAME_C = "log_C.txt";
	// 與客戶端相連的Socket
	protected Socket csocket;

	public MyHttpProxy(Socket cs) {
		csocket = cs;
		start();
	}

	public void writeLog(int c, boolean browser) throws IOException {
		if (browser)
			log_C.write((char) c);
		else
			log_S.write((char) c);
	}

	public void writeLog(byte[] bytes, int offset, int len, boolean browser)
			throws IOException {
		for (int i = 0; i < len; i++)
			writeLog((int) bytes[offset + i], browser);
	}

	public void run() {
		String buffer = ""; // 讀取請求頭
		String URL = ""; // 讀取請求URL
		String host = ""; // 讀取目標主機host
		int port = 80; // 默認端口80
		Socket ssocket = null;
		// cis爲客戶端輸入流,sis爲目標主機輸入流
		InputStream cis = null, sis = null;
		// cos爲客戶端輸出流,sos爲目標主機輸出流
		OutputStream cos = null, sos = null;
		try {
			csocket.setSoTimeout(TIMEOUT);
			cis = csocket.getInputStream();
			cos = csocket.getOutputStream();
			while (true) {
				int c = cis.read();// ?此處好多timeout異常。
				if (c == -1)
					break; // -1爲結尾標誌
				if (c == '\r' || c == '\n')
					break;// 讀入第一行數據
				buffer = buffer + (char) c;
				if (logging)
					writeLog(c, true);
			}
			// 抽取URL
			URL = getRequestURL(buffer);

			int n;
			// 抽取host
			n = URL.indexOf("//");
			if (n != -1)
				host = URL.substring(n + 2); // www.baidu.com/
			n = host.indexOf('/');
			if (n != -1)
				host = host.substring(0, n);// www.baidu.com

			// 分析可能存在的端口號
			n = host.indexOf(':');
			if (n != -1) {
				port = Integer.parseInt(host.substring(n + 1));
				host = host.substring(0, n);
			}
			int retry = CONNECT_RETRIES;
			while (retry-- != 0) {
				try {
					ssocket = new Socket(host, port); // 嘗試建立與目標主機的連接
					break;
				} catch (Exception e) {
				}
				// 等待
				Thread.sleep(CONNECT_PAUSE);
			}
			if (ssocket != null) {
				ssocket.setSoTimeout(TIMEOUT);
				sis = ssocket.getInputStream();
				sos = ssocket.getOutputStream();
				sos.write(buffer.getBytes()); // 將請求頭寫入
				pipe(cis, sis, sos, cos); // 建立通信管道
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (csocket != null)
					csocket.close();
				if (cis != null)
					cis.close();
				if (cos != null)
					cos.close();
			} catch (Exception e1) {
				System.out.println("\nClient Socket Closed Exception:");
				e1.printStackTrace();
			}
			try {
				if (ssocket != null)
					ssocket.close();
				if (sis != null)
					sis.close();
				if (sos != null)
					sos.close();
			} catch (Exception e2) {
				System.out.println("\nServer Socket Closed Exception:");
				e2.printStackTrace();
			}
		}
	}

	public String getRequestURL(String buffer) {
		String[] tokens = buffer.split(" ");
		String URL = "";
		for (int index = 0; index < tokens.length; index++) {
			if (tokens[index].startsWith("http://")) {
				URL = tokens[index];
				break;
			}
		}
		return URL;
	}

	public void pipe(InputStream cis, InputStream sis, OutputStream sos,
			OutputStream cos) {
		try {
			int length;
			byte bytes[] = new byte[BUFSIZ];
			while (true) {
				try {
					if ((length = cis.read(bytes)) > 0) {
						sos.write(bytes, 0, length);
						if (logging)
							writeLog(bytes, 0, length, true);
					} else if (length < 0)
						break;
				} catch (SocketTimeoutException e) {
				} catch (InterruptedIOException e) {
					System.out.println("\nRequest Exception:");
					e.printStackTrace();
				}
				try {
					if ((length = sis.read(bytes)) > 0) {
						cos.write(bytes, 0, length);
						if (logging)
							writeLog(bytes, 0, length, false);
					} else if (length < 0)
						break;
				} catch (SocketTimeoutException e) {
				} catch (InterruptedIOException e) {
					System.out.println("\nResponse Exception:");
					e.printStackTrace();
				}
			}
		} catch (Exception e0) {
			System.out.println("Pipe異常:" + e0);
		}
	}

	public static void startProxy(int port, Class clobj) {
		try {
			ServerSocket ssock = new ServerSocket(port);
			while (true) {
				Class[] sarg = new Class[1];
				Object[] arg = new Object[1];
				sarg[0] = Socket.class;
				try {
					java.lang.reflect.Constructor cons = clobj
							.getDeclaredConstructor(sarg);
					arg[0] = ssock.accept();//當某些客戶機與serverSocket連接時,創建一個新的套接字,稱爲socket
					cons.newInstance(arg); // 創建HttpProxy或其派生類的實例
				} catch (Exception e) {
					Socket esock = (Socket) arg[0];
					try {
						esock.close();
					} catch (Exception ec) {
					}
				}
			}
		} catch (IOException e) {
			System.out.println("\nStartProxy Exception:");
			e.printStackTrace();
		}
	}

	// 測試用的簡單main方法
	static public void main(String args[]) throws FileNotFoundException {
		System.out.println("在端口808啓動代理服務器\n");
		OutputStream file_S = new FileOutputStream(new File(LOGFILENAME_S));
		OutputStream file_C = new FileOutputStream(new File(LOGFILENAME_C));
		MyHttpProxy.log_S = file_S;
		MyHttpProxy.log_C = file_C;
		MyHttpProxy.logging = true;
		MyHttpProxy.startProxy(808, MyHttpProxy.class);
	}

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章