为了通过客户的机子代理上外网,不能用ccproxy只好自己写了一个:
so simple , so easy ! But all my colleagues are so surprised . So , I am very
surprised !
首先需要一个线程缓冲池,和数据库连接池很不一样,两个类:
import java.util.*;
/**
* 描述:
*
* @author $张忠强$
* @version $Revision$
*/
public class ThreadPool {
protected Thread [] threads = null;
Collection assignments = new ArrayList(3); //初始为3个元素,动态增减。
protected Done done = new Done();
private static ThreadPool pool = null;
//连接池配置-应从配置文件中读取
static int threadSize = 10;
//
public static ThreadPool getInstance() {
if (pool == null) {
pool = new ThreadPool(threadSize);
}
return pool;
}
/**
* 构造一个新的 ThreadPool 对象.
*
* @param size 描述:
*/
private ThreadPool(int size) {
threads = new WorkerThread[ size ];
for (int i = 0; i < threads.length; i++) {
threads [ i ] = new WorkerThread(this);
threads [ i ].start ();
}
}
/**
* 描述:注册要执行的任务
*
* @param r 描述:
*/
public synchronized void assign(Runnable r) {
done.workerBegin ();
assignments.add (r);
notify ();
}
/**
* 描述:
*
* @return 描述:
*/
public synchronized Runnable getAssignment() {
try {
while (!assignments.iterator ().hasNext ())
wait ();
Runnable r = (Runnable) assignments.iterator ().next ();
assignments.remove (r);
return r;
}
catch (InterruptedException e) {
done.workerEnd ();
return null;
}
}
/**
* 描述:
*/
public void complete() {
done.waitBegin ();
done.waitDone ();
}
/**
* 描述:
*/
protected void finalize() {
done.reset ();
for (int i = 0; i < threads.length; i++) {
threads [ i ].interrupt ();
done.workerBegin ();
//threads[i].destroy();
}
done.waitDone ();
}
}
/**
* 描述:执行任务的线程对象
*
* @author $author$
* @version $Revision$
*/
class WorkerThread extends Thread {
public boolean busy;
public ThreadPool owner;
/**
* 构造一个新的 WorkerThread 对象,并关联到池.
*
* @param o 描述:
*/
WorkerThread(ThreadPool o) {
owner = o;
}
/**
* 描述:实现接口
*/
public void run() {
Runnable target = null;
do {
target = owner.getAssignment ();
if (target != null) {
target.run ();
owner.done.workerEnd ();
}
}
while (target != null);
}
}
/**
* 描述:
*
* @author $张忠强$
* @version $Revision$
*/
public class Done {
private int activeThreads = 0;
private boolean started = false;
/**
* 描述:
*/
public synchronized void waitDone() {
try {
while (activeThreads > 0) {
wait ();
}
}
catch (InterruptedException e) {
}
}
/**
* 描述:
*/
public synchronized void waitBegin() {
try {
while (!started) {
wait ();
}
}
catch (InterruptedException e) {
}
}
/**
* 描述:
*/
public synchronized void workerBegin() {
activeThreads++;
started = true;
notify ();
}
/**
* 描述:
*/
public synchronized void workerEnd() {
activeThreads--;
notify ();
}
/**
* 描述:
*/
public synchronized void reset() {
activeThreads = 0;
}
}
服务线程:
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* 描述:
*
* @author $张忠强$
* @version $Revision$
*/
public class DataService implements Runnable {
int CONNECT_RETRIES = 5;
int CONNECT_PAUSE = 5;
int TIMEOUT = 50; //socket超时设置
int BUFSIZ = 1024 * 5; //缓冲区
boolean loging = false; //是否输出日志信息
//和此线程关联的Socket,用于和客户端交换数据
Socket socket;
//输出日志
public void log(String log) {
if (loging) {
System.out.println (log);
}
}
/**
* DOCUMENT ME!
*
* @param s 描述:
*/
public DataService(Socket s) {
socket = s;
}
//对请求的每一个图元进行服务的线程
public void run() {
String line;
String host;
int port = 80; //默认
Socket outbound = null;
try {
socket.setSoTimeout (TIMEOUT);
InputStream is = socket.getInputStream ();
OutputStream os = null;
// 获取请求行的内容
line = "";
host = "";
int state = 0;
boolean space;
while (true) {
int c = is.read ();
if (c == -1) {
break;
}
space = Character.isWhitespace ((char) c);
switch (state) {
case 0:
if (space) {
continue;
}
state = 1;
case 1:
if (space) {
state = 2;
continue;
}
line = line + (char) c;
break;
case 2:
if (space) {
continue; // 跳过多个空白字符
}
state = 3;
case 3: //----------------------------------------------------------
if (space) {
state = 4;
// 只取出主机名称部分
String host0 = host;
int n;
n = host.indexOf ("//");
if (n != -1) {
host = host.substring (n + 2);
}
n = host.indexOf ('/');
if (n != -1) {
host = host.substring (0, n);
}
// 分析可能存在的端口号
n = host.indexOf (":");
if (n != -1) {
port = Integer.parseInt (host.substring (n +
1));
host = host.substring (0, n);
}
//如果存在上级代理,则不用进行以上操作,直接和代理通讯
int retry = CONNECT_RETRIES;
//尝试连接远程目标,CONNECT_RETRIES次
while (retry-- != 0) {
try {
outbound = new Socket(host, port);
break;
}
catch (Exception e) {
//System.out.println ("重试...");
}
// 等待
Thread.sleep (CONNECT_PAUSE);
}
if (outbound == null) {
break;
}
outbound.setSoTimeout (TIMEOUT);
os = outbound.getOutputStream (); //向远程服务器写入请求
os.write (line.getBytes ());
os.write (' ');
os.write (host0.getBytes ());
os.write (' ');
pipe (is, outbound.getInputStream (), os,
socket.getOutputStream ());
break; //跳出case 3
}
host = host + (char) c;
break;
//-------------------------------------------------------------
}
}
}
catch (Exception e) {
}
finally {
try {
socket.close ();
}
catch (Exception e1) {
}
try {
outbound.close ();
}
catch (Exception e2) {
}
}
}
/**
* 描述:数据传送桥
*
* @param is0 描述:读取客户的请求信息
* @param is1 描述:读取远程服务器返回数据
* @param os0 描述:向远程服务器写入请求信息
* @param os1 描述:向客户端写入服务器返回数据
*/
void pipe(InputStream is0, InputStream is1, OutputStream os0,
OutputStream os1) {
try {
int ir;
byte [] bytes = new byte[ BUFSIZ ];
while (true) {
try {
if ((ir = is0.read (bytes)) > 0) {
os0.write (bytes, 0, ir);
//System.out.println (new String(bytes).trim ());
}
else if (ir < 0) {
break;
}
}
catch (InterruptedIOException e) {
}
try {
if ((ir = is1.read (bytes)) > 0) {
os1.write (bytes, 0, ir);
}
else if (ir < 0) {
break;
}
}
catch (InterruptedIOException e) {
}
}
}
catch (Exception e0) {
//System.out.println ("Pipe异常: " + e0);
}
}
}
主类:
import java.io.*;
import java.net.*;
/**
* 描述:代理服务器类
*
* @author $张忠强$
* @version $1.0$
*/
public class HttpProxy {
/*/上级代理服务器地址和端口
private static String parent = null;
private static int parentPort = -1;
/**
* 描述:设置上级代理地址和端口,可选方法
*
* @param name 描述:
* @param pport 描述:
*/
/*
public static void setParentProxy(String name, int pport) {
parent = name;
parentPort = pport;
}*/
/**
* 描述:开启代理服务
*
* @param port 描述:
*/
public static void startProxy(int port) {
ServerSocket ssock = null;
ThreadPool pool = ThreadPool.getInstance ();
try {
ssock = new ServerSocket(port);
System.out.println ("在端口25启动代理服务器/n");
//浏览器对同一页面上的不同图元采用不同的线程进行请求的
//所以用不同的线程进行服务
//一个页面使用的线程数和其图元数一致
//所以采用线程池是必要的
while (true) {
Socket tmp = ssock.accept ();
pool.assign (new DataService(tmp));
}
}
catch (IOException e) {
e.printStackTrace ();
}
finally {
pool.complete ();
if (ssock != null) {
try {
ssock.close ();
}
catch (Exception e) {
}
}
}
}
// 测试用的简单main方法
public static void main(String [] args) {
HttpProxy.startProxy (25);
}
}
可以将其植入servlet中,达到真正的隐藏。。。