JAVA实现网络请求代理之Socket篇

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 即可,大家不妨下来试一试。


你可能感兴趣的:(Socket代理,java代理服务)