java代理服务代码 java代理ip( 四 )


return host;
}
表一
变量/方法 说明
CONNECT_RETRIES 在放弃之前尝试连接远程主机的次数 。
CONNECT_PAUSE 在两次连接尝试之间的暂停时间 。
TIME-OUT 等待Socket输入的等待时间 。
BUFSIZ Socket输入的缓冲大小 。
logging 是否要求代理服务器在日志中记录所有已传输的数据(true表示“是”) 。
log 一个OutputStream对象,默认日志例程将向该OutputStream对象输出日志信息 。
setParentProxy 用来把一个代理服务器链接到另一个代理服务器(需要指定另一个服务器的名称和端口) 。
当代理服务器连接到Web服务器之后,我用一个简单的循环在两个Socket之间传递数据 。这里可能出现一个问题,即如果没有可操作的数据,调用read方法可能导致程序阻塞,从而挂起程序 。为防止出现这个问题,我用setSoTimeout方法设置了Socket的超时时间(参见Listing 2) 。这样,如果某个Socket不可用,另一个仍旧有机会进行处理 , 我不必创建一个新的线程 。
【Listing 2】
// 执行操作的线程
public void run() {
String line;
String host;
int port=80;
Socket outbound=null;
try {
socket.setSoTimeout(TIMEOUT);
InputStream is=socket.getInputStream();
OutputStream os=null;
try {
// 获取请求行的内容
line="";
host="";
int state=0;
boolean space;
while (true) {
int c=is.read();
if (c==-1) break;
if (logging) writeLog(c,true);
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);
}
host=processHostName(host0,host,port,socket);
if (parent!=null) {
host=parent;
port=parentPort;
}
int retry=CONNECT_RETRIES;
while (retry--!=0) {
try {
outbound=new Socket(host,port);
break;
} catch (Exception e) { }
// 等待
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;
}
host=host+(char)c;
break;
}
}
}
catch (IOException e) { }
} catch (Exception e) { }
finally {
try { socket.close();} catch (Exception e1) {}
try { outbound.close();} catch (Exception e2) {}
}
}
和所有线程对象一样,HttpProxy类的主要工作在run方法内完成(见Listing 2) 。run方法实现了一个简单的状态机,从Web浏览器每次一个读取字符,持续这个过程直至有足够的信息找出目标Web服务器 。然后,run打开一个通向该Web服务器的Socket(如果有多个代理服务器被链接在一起,则run方法打开一个通向链里面下一个代理服务器的Socket) 。打开Socket之后,run先把部分的请求写入Socket,然后调用pipe方法 。pipe方法直接在两个Socket之间以最快的速度执行读写操作 。
如果数据规模很大,另外创建一个线程可能具有更高的效率;然而,当数据规模较小时,创建新线程所需要的开销会抵消它带来的好处 。