Posted on 2009-12-13 15:45
啥都写点 阅读(257)
评论(0) 编辑 收藏 所属分类:
J2SE
本实例实现了一个代理服务器,实质上是实现了一个代理服务,部署在前文实现的通用服务器框架上。用户需要指定目标服务器的IP地址和端口,然后在浏览器中输入本地网址,便可以访问目标服务器上的网页。
代理服务作为一个服务部署在服务器框架上,必须实现book.net.GeneraServer$Service接口,实现它的serve方法。
当客户端请求代理服务时,客户端与代理服务之间会建立socket,代理服务收到请求后,会与目标服务器建立Socket。
代理服务持有两个Socket,它起中转作用,将来自客户端的请求转发给服务器,来自服务器端的响应消息转发给客户端,可以通过两个线程分别处理请求消息的转发和响应消息的转发。
import java.io.*;
import java.net.*;
/** *//**
* 本类为支持多线程服务器框架的GeneralServer类提供了一个相关的服务Service,
* 使GeneralServer提供代理服务。内部类ProxyService实现了GeneralServer.Service接口。
**/
public class ProxyServer {
// 命令行的格式是:代理服务器连接的目标服务器的域名、端口以及代理服务开启的本地端口
public static final String usage =
"Usage: java book.net.ProxyServer <remotehost> <remoteport> <localport> ";
/** *//**
* 创建一个GeneralServer对象,并添加代理服务ProxyService对象到这个服务器上。
**/
public static void main(String[] args) {
try {
// 检验参数
if ((args.length == 0) || (args.length % 3 != 0)){
throw new IllegalArgumentException("Wrong number of args");
}
// 创建一个服务器:GeneralServer对象,用于管理服务,
// 第一个参数为null表示服务器的日志输出在标准输出上,第二个参数12表示最大连接数
GeneralServer server = new GeneralServer(null, 12);
// 从命令行中解析参数,可以创建多个代理服务
int i = 0;
while(i < args.length) {
// 目标服务器的域名和地址
String remotehost = args[i++];
int remoteport = Integer.parseInt(args[i++]);
// 代理服务在本地的端口
int localport = Integer.parseInt(args[i++]);
// 创建一个连接到目标服务器的代理服务对象,并部署在本地服务器上的localport端口上。
server.addService(new ProxyService(remotehost, remoteport), localport);
}
}
catch (Exception e) {
System.err.println(e);
System.err.println(usage);
System.exit(1);
}
}
/** *//**
* 实现代理服务的功能,实现了GeneralServer.Service接口的serve方法。
* 首先与目标服务器建立连接,然后将来自客户端的输入流输出到目标服务器端,
* 将来自目标服务器的输入流输出到客户端。
* 输入输出流的流向控制是通过2个线程实现的。
*/
public static class ProxyService implements GeneralServer.Service {
// 目标服务器的域名和端口
String remotehost;
int remoteport;
/** *//**
* 构造方法
*/
public ProxyService(String host, int port) {
this.remotehost = host;
this.remoteport = port;
}
/** *//**
* 当客户端调用GeneralServer上的代理服务时,将调用serve方法
*/
public void serve(InputStream in, OutputStream out) {
// 来自客户端的输入流
final InputStream from_client = in;
// 输出到客户端的输出流
final OutputStream to_client = out;
// 与目标服务器的输入输出流
final InputStream from_server;
final OutputStream to_server;
// 连接到目标服务器的socket对象
final Socket server;
try {
// 连接目标服务器,初始化from_server,to_server流
server = new Socket(remotehost, remoteport);
from_server = server.getInputStream();
to_server = server.getOutputStream();
} catch (Exception e) {
// 如果连接失败,则向客户端发送失败的消息
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
pw.print("Proxy server could not connect to " + remotehost
+ ":" + remoteport + "\n");
pw.flush();
pw.close();
try {
in.close();
} catch (IOException ex) {
}
return;
}
// 创建一个线程,将来自客户端的输入流字节输出到目标服务器上
Thread client2server = new Thread() {
public void run() {
byte[] buffer = new byte[2048];
int bytes_read;
try {
// 从来自客户端的输入流中读取数据,写到目标服务器上
while ((bytes_read = from_client.read(buffer)) != -1) {
to_server.write(buffer, 0, bytes_read);
to_server.flush();
}
} catch (IOException e) {
} finally {
// 当线程结束时,关闭与目标服务器的socket连接和2个输入输出流
try {
server.close();
to_client.close();
from_client.close();
} catch (IOException e) {
}
}
}
};
// 创建一个线程,用于将来自目标服务器的输入流输出到客户端
Thread server2client = new Thread() {
public void run() {
byte[] buffer = new byte[2048];
int bytes_read;
try {
// 读取来自目标服务器的输入流from_server,然后输出到to_client
while ((bytes_read = from_server.read(buffer)) != -1) {
to_client.write(buffer, 0, bytes_read);
to_client.flush();
}
} catch (IOException e) {
} finally {
try {
server.close();
to_client.close();
from_client.close();
} catch (IOException e) {
}
}
}
};
// 启动这两个线程
client2server.start();
server2client.start();
// 当这个两个线程运行结束时,本次服务才结束
try {
client2server.join();
server2client.join();
} catch (InterruptedException e) {
}
}
}
}
在命令行下输入"java book.net.ProxyServer
www.google.com 80 5555",将启动代理服务器,端口为5555.打开浏览器,在地址栏中输入'
http://localhost:5555 " 将会打开
www.google.com的主页。
-- 学海无涯