JAVA实现网络请求代理之HTTP篇 (一)
JAVA实现网络请求代理之Socket篇(二)
Java代理服务器之截取,篡改HTTP请求(应用篇)
用Java实现Socket代理服务,原理上和http代理有些相似,只是两种协议的格式不一样。socket是对tcp/ip协议的抽象封装,所以socket的格式和tcp/ip的协议是不一样的。
具体详细的Socket 和tcp/ip 的关系大家可以参考 http://www.2cto.com/net/201211/166537.html 这篇博文。
下面还是继续贴上代码,供大家研究
package com.mato.proxy.socket; import java.net.ServerSocket; import java.net.Socket; /** * Created by cjl on 2015/9/9. */ public class SOCKETProxy extends Thread{ private ServerSocket server; public SOCKETProxy(ServerSocket _server){ server=_server; start(); } public void run(){ // 线程运行函数 Socket connection; while(true){ try{ connection=server.accept(); SOCKSServerThread handler =new SOCKSServerThread(connection); }catch(Exception e){} } } }
接下来就是socket 连接的具体处理类。
package com.mato.proxy.socket; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; /** * Created by cjl on 2015/9/8. */ public class SOCKSServerThread extends Thread{ private Socket client; int bytes2int(byte b){ // 将 byte 类型转换为 int 类型 int mask=0xff; int temp=0; int res=0; res<<=8; temp=b&mask; res|=temp; return res; } public SOCKSServerThread(Socket _connection){ // 构造函数 client =_connection; start(); } public void run(){ // 线程运行函数 byte creadBuf[]=new byte[10000],cwriteBuf[]=new byte[10000],buf2[]=new byte[10000]; int creadlen=0,sreadlen=0,readbytes2=0; DataInputStream cin=null,sin=null; DataOutputStream cout=null,sout=null; String s=null,s1=null,s2=null; int i; int port=0,port1=0; String ip=null; Socket server=null; byte ip1[]=new byte[4],ip2[]=new byte[4]; try{ cin=new DataInputStream(client.getInputStream()); cout =new DataOutputStream (client.getOutputStream()); if(cin!=null&&cout!=null){ creadlen=cin.read(creadBuf,0,10000); // 从客户端读数据 if(creadlen>0){ // 读到数据 if(creadBuf[0]==5){ // 读到 SOCK5 请求 // 发送 SOCK5 应答,第一次 cwriteBuf[0]=5;cwriteBuf[1]=0; cout.write(cwriteBuf,0,2); cout.flush(); creadlen=cin.read(creadBuf,0,10000); // 继续读 SOCK5 请求 if(creadlen>0){ // 读到 SOCK5 请求 if(creadBuf[0]==5&&creadBuf[1]==1&&creadBuf[2]==0&&creadBuf[3]== 1){//TCP 请求 // 从该请求中取要连接的 IP 地址和端口号 , 并建立TCP 套接字 ip=bytes2int(creadBuf[4])+"."+bytes2int(creadBuf[5])+"."+ bytes2int(creadBuf[6])+"."+bytes2int(creadBuf[7]); port=creadBuf[8]*256+creadBuf[9]; server=new Socket(ip,port);//创建到远程服务端的套接字 sin = new DataInputStream(server.getInputStream()); sout = new DataOutputStream(server.getOutputStream()); // 发送 SOCK5 应答 ip1 = server.getLocalAddress().getAddress(); port1 = server.getLocalPort(); creadBuf[1] = 0; creadBuf[4] = ip1[0]; creadBuf[5] = ip1[1]; creadBuf[6] = ip1[2]; creadBuf[7] = ip1[3]; creadBuf[8] = (byte) (port1 >> 8); creadBuf[9] = (byte) (port1 & 0xff); cout.write(creadBuf, 0, 10);//回复应答,第二次 cout.flush(); // 建立线程 , 用于给客户端返回数据 SOCKETChannel channel = new SOCKETChannel(sin, cout); while(true){ // 循环读数据 try { if (sreadlen == -1) break; // 无数据则退出循环 sreadlen = cin.read(cwriteBuf, 0, 10000); // 从客户端读数据 if (sreadlen > 0) { // 读到数据 , 则发送给外网 sout.write(cwriteBuf, 0, sreadlen); sout.flush(); } }catch(Exception e1){break;} } } } } if(creadBuf[0]==4){ // 读到 SOCK4 请求 port=creadBuf[2]*256+creadBuf[3]; // 从请求中取端口号 if(creadBuf[4]==0&&creadBuf[5]==0&&creadBuf[6]==0&&creadBuf[7]!= 0&&creadBuf[8]==0){ // 如请求中为域名 s=new String(creadBuf); s=s.substring(9); s=s.substring(0,s.indexOf("\0")); } else{ // 如请求中为 IP 地址 ip=bytes2int(creadBuf[4])+"."+bytes2int(creadBuf[5])+"."+bytes2int(creadBuf[6])+"."+bytes2int(creadBuf[7]); s=ip; } for(i=1;i<=9;i++) creadBuf[i-1]=0; server=new Socket(s,port); // 根据 SOCK4 请求中的地址建立 TCP 套接字 sin=new DataInputStream(server.getInputStream()); sout =new DataOutputStream(server.getOutputStream()); // 返回 SOCK4 应答,第二次 ip1=server.getLocalAddress().getAddress(); port1=server.getLocalPort(); creadBuf[0]=0; creadBuf[1]=0x5a; creadBuf[2]=ip1[0]; creadBuf[3]=ip1[1]; creadBuf[4]=(byte)(port1>>8); creadBuf[5]=(byte)(port1&0xff); cout.write(creadBuf,0,8); cout.flush(); // 建立线程 , 用于给客户端返回数据 SOCKETChannel thread1 = new SOCKETChannel(sin, cout); while(true){ // 循环读数据 try { if (sreadlen == -1) break; // 无数据则退出循环 sreadlen = cin.read(cwriteBuf, 0, 10000); // 从客户端读数据 if (sreadlen > 0) { // 读到数据 , 则发送给外网 sout.write(cwriteBuf, 0, sreadlen); sout.flush(); } }catch(Exception e1){break;} } } } } // 执行关闭操作 if(sin!=null) sin.close(); if(sout!=null) sout.close(); if(server!=null) server.close(); if(cin!=null) cin.close(); if(cout!=null) cout.close(); if(client !=null) client.close(); }catch(IOException e){} } }
再接下来就是socket 建立传输通道的线程类
package com.mato.proxy.socket; import java.io.DataInputStream; import java.io.DataOutputStream; /** * Created by cjl on 2015/9/8. */ public class SOCKETChannel extends Thread{ private DataInputStream in; // 读数据 private DataOutputStream out; // 写数据 public SOCKETChannel(DataInputStream _in, DataOutputStream _out){ in=_in; out=_out; start(); } public void run(){ // 线程运行函数 , 循环读取返回数据 , 并发送给相关客户端 int readbytes=0; byte buf[]=new byte[10000]; while(true){ // 循环 try{ if(readbytes==-1) break; // 无数据则退出循环 readbytes=in.read(buf,0,10000); if(readbytes>0){ out.write(buf,0,readbytes); out.flush(); } }catch(Exception e){break;} // 异常则退出循环 } } }
最后就是一个Main启动
package com.mato.proxy; import com.mato.proxy.http.HttpProxy; import com.mato.proxy.socket.SOCKETProxy; import java.io.IOException; import java.net.ServerSocket; /** * Created by cjl on 2015/9/8. */ public class Proxy { public static void main(String[] args) { try{ ServerSocket httpserver=new ServerSocket(808); // 建立 HTTP 侦听套接字 System.out.println ("HTTP Proxy started on "+httpserver.getLocalPort()); ServerSocket socksserver=new ServerSocket(888); // 建立 SOCKS 侦听套接字 System.out.println ("SOCKS Proxy started on "+socksserver. getLocalPort()); HttpProxy httpproxy=new HttpProxy(httpserver); // 建立HTTP 侦听线程 SOCKETProxy socksproxy=new SOCKETProxy(socksserver); // 建立 SOCKS 侦听线程 }catch(IOException e){} } }
其中包括昨天的http代理服务的启动,socket代理只是实现了tcp协议的,如果要实现UDP协议的话,按照其协议格式进行解析,socket类替换成DatagramSocket 即可,大家不妨下来试一试。