用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){}
}
}
}
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){}
}
}
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;} // 异常则退出循环
}
}
}
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){}
}
}
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 即可,大家不妨下来试一试。