这里实现了一个基础的代理服务器,就是socket管道的跳转,但是对于应用中的代理服务器,其中必有很多东西是要注意的,考虑的,这里的代码仅仅是为了使你去了解代理服务器的一个简单流程
代理服务器类
package com.inetAddressTest.proxy;
import jdk.internal.util.xml.impl.Input;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Objects;
/**
* Created by Administrator on 2017/5/1.
*/
public class MyHttpProxy extends Thread {
//尝试重新连接次数
public static int CONNECT_RETRIES=5;
//尝试重连中间停顿的次数
public static int CONNECT_PAUSE=5;
//超时连接时间
public static int TIME_OUT=50;
//是否计入日志信息
public static boolean logging=false;
//日志输出位置
public static OutputStream out=null;
//设置代理服务器地址,默认为本地的8080
private static InetSocketAddress address=new InetSocketAddress("localhost",8080);
//设置父类代理服务器的地址
private static InetSocketAddress pAddress=null;
//
private Socket socket;
public static void setParentProxy(InetSocketAddress address){
pAddress=address;
}
public MyHttpProxy(Socket socket){
this.socket=socket;
start();
}
public void writeLog(int c, boolean browser) throws IOException {
out.write(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 String proccessHostName(String url,String host,int port,Socket socket){
DateFormat df=DateFormat.getInstance();
System.out.println(df.format(new Date()+" "+url+" "+host+" "+port+" "+socket.getInetAddress()));
return host;
}
/**
* 该方法用于通道的转换
* @param in0 from
* @param in1
* @param out1 to
* @param out2
*/
public void pipe(InputStream in0,InputStream in1,OutputStream out1,OutputStream out2){
int a=0;
byte[] buff=new byte[1024];
try {
while ((a=in0.read(buff))!=-1){
out1.write(buff,0,a);
writeLog(buff,0,a,true);
}
} catch (IOException e) {
//捕捉到异常时将流写回原来的流
try {
while ((a=in1.read(buff))!=-1){
out2.write(buff,0,a);
writeLog(buff,0,a,true);
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
@Override
public void run() {
//被代理服务器的socket
Socket outBound=null;
String host="127.0.0.1";
int port=8900;
if(pAddress!=null){
host=pAddress.getHostName();
port=pAddress.getPort();
}
//尝试连接次数
int retry=CONNECT_RETRIES;
try {
while(true){
try {
outBound=new Socket(host,port);
break;
} catch (IOException e) {
try {
//连接失败后尝试连接等到时间
Thread.sleep(CONNECT_PAUSE);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
if(outBound!=null){
outBound.setSoTimeout(TIME_OUT);
//转换通道
pipe(socket.getInputStream(),outBound.getInputStream(),outBound.getOutputStream(),socket.getOutputStream());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 客服端设置代理对象
* @param address0 代理服务器地址
* @param proxy 代理类,可为HttpProxy的子类
*/
public static void setProxy(InetSocketAddress address0,Class<MyHttpProxy> proxy){
if(address!=null){
address=address0;
}
ServerSocket serverSocket=null;
Socket socket=null;
try {
serverSocket=new ServerSocket(address.getPort());
while (true){
//用反射通过构造函数来得到代理类的实例
Class[] sarg=new Class[1];
Object[] oarg=new Object[1];
sarg[0]=Socket.class;
try {
Constructor<MyHttpProxy> cons=proxy.getDeclaredConstructor(sarg);
oarg[0]=serverSocket.accept();
cons.newInstance(oarg);//每次接受到连接都要实例化一个对象//实际运用在是否应该考虑一下缓存问题
} catch (Exception e) {
((Socket)oarg[0]).close();
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("启动代理服务器");
MyHttpProxy.logging=true;
MyHttpProxy.out=System.out;
MyHttpProxy.setProxy(new InetSocketAddress("localhost",8080),MyHttpProxy.class);
}
}
被代理类
package com.inetAddressTest.proxy;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by Administrator on 2017/5/1.
*/
public class SocketServerTest {
public static void main(String[] args) throws Exception{
System.out.println("启动了服务器");
ServerSocket serverSocket=new ServerSocket(8900);
while (true){
Socket socket=serverSocket.accept();
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line="";
while ((line=reader.readLine())!=null){
System.out.println(line);
}
}
}
}