python java程序使用Clash HTTP和SOCKS5代理及API动态换IP

HTTP和SOCKS5代理和区别

HTTP和SOCKS5是两种常见的代理协议,它们在数据传输方式和使用场景上有一些不同。

  1. HTTP代理:HTTP代理主要用于HTTP协议的数据传输,它在客户端和服务器之间起到一个中间人的作用,帮助用户获取、发送数据。HTTP代理只处理HTTP和HTTPS的网络流量,因此主要用于网页浏览等场景。HTTP代理可以读取并修改传输的数据,还可以对HTTP头进行操作,因此使用时要注意隐私和安全问题。
  2. SOCKS5代理:SOCKS5代理是一个更高级的协议,它支持任何类型的网络流量,包括TCP和UDP,因此可以用于更多的场景,如FTP、SMTP等各种应用层协议。SOCKS5代理只负责将数据包从源传输到目标,不关心数据的内容,因此它对数据包的处理更少,速度更快,但也意味着它不能提供像HTTP代理那样的数据修改功能。SOCKS5代理还支持各种身份验证方法,因此在安全性上比HTTP代理更有优势。

总的来说,HTTP代理和SOCKS5代理的主要区别在于数据处理方式和使用范围。HTTP代理主要用于处理HTTP/HTTPS流量,可以修改数据,但安全性较低;SOCKS5代理可以处理任何类型的网络流量,数据处理少,速度快,安全性较高。

HTTP代理默认会在HTTP请求头中加上源IP,容易泄露自身IP。SOCKS5匿名性较高。

准备工作

1.设置Clash代理端口

默认是7890端口,同时支持HTTP和SOCKS5,一般可不修改。

2.设置Clash restfull API端口

在主界面点击Home Directory主目录项的“Open Folder”打开文件夹,进入配置根文件目录下。

python java程序使用Clash HTTP和SOCKS5代理及API动态换IP
主界面
python java程序使用Clash HTTP和SOCKS5代理及API动态换IP
配置根文件

右边编辑config.yaml文件,查看external-controller一项的配置。以下是一个配置示例:

mixed-port: 7890
allow-lan: true
external-controller: 127.0.0.1:53365
secret: 29c0c9ba-1740-42c0-bb8c-dd316c5d1e4a
ipv6: false
log-level: info

其中external-controller表示Clash HTTP API的接口地址。如果需要让局域网访问,可将IP调整为0.0.0.0,并且设置allow-lan允许局域网流量。

secret为Clash HTTP API的密码,需要在API请求头加入“Authorization:Bearer ${secret}”。

代码编写

1.程序使用Clash的SOCKS5代理(JAVA为例)

此处使用了OkHttp的工具包,示例代码:

maven依赖引入:

            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>4.9.2</version>
            </dependency>

    public static Response searchByProxy(String url ){
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 53365))
        try {
            // 创建OkHttpClient
            client = new OkHttpClient.Builder()
                    .proxy(proxy)
                    .connectTimeout(60, TimeUnit.SECONDS)
                    .readTimeout(60, TimeUnit.SECONDS)
                    .writeTimeout(60, TimeUnit.SECONDS)
                    .build();
            // 创建请求
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("Accept-Language", "en-US")
                    .addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36")
                    .build();
            Response response = client.newCall(request).execute();
            return response;
        } catch (Exception e) {
            log.error("请求失败,error:{}",e.getMessage());
            return null;
        }
    }

2.程序自动换IP

主要过程是使用clash restfull接口获取全部节点,剔除不可用的节点和延迟较高节点,然后使用API换节点。

此处使用了hutool的工具包,引入依赖:

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.19</version>
        </dependency>

编写工具类:


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ClashUtil {

    private static final Logger log = LoggerFactory.getLogger(ClashUtil.class);


    /**
     * clash配置
     * external-controller: 127.0.0.1:61920
     * secret: 4a1c185f-607e-4ec6-a984-bab952503d5d
     */

    public static  String clashApiUrl = "http://127.0.0.1:61920";

    public static  String secret = "4a1c185f-607e-4ec6-a984-bab952503d5d";

    public static  String selectorName = "GLOBAL";

    public static String curNode = null;

    public static final List<String> excludeNodes = Arrays.asList(new String[]{"自动选择","故障转移","DIRECT","REJECT"});

    public static List<String> getAllNode(){
        HttpRequest request = HttpUtil.createGet(clashApiUrl+"/proxies");
        if(StrUtil.isNotEmpty(secret)){
            request.header("Authorization","Bearer "+secret);
        }
        String result = request.execute().body();
        if(StrUtil.isEmpty(result) || !JSONUtil.isTypeJSONObject(result)){
            return null;
        }
        JSONObject resultObj = JSONUtil.parseObj(result).getJSONObject("proxies");
        JSONArray jsonArray = resultObj.getJSONObject(selectorName).getJSONArray("all");
        List<String> validNodeList = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            String itemNodeName = jsonArray.getStr(i);
            boolean isExcludeNodes = false;
            for (String excludeNode : excludeNodes) {
                if(itemNodeName.contains(excludeNode)){
                    isExcludeNodes = true;
                    break;
                }
            }
            if(isExcludeNodes){
                continue;
            }
            //延迟计算
            JSONObject nodeDelay = resultObj.getJSONObject(itemNodeName);
            //失效节点
            if(nodeDelay==null  || nodeDelay.getJSONArray("history")==null || nodeDelay.getJSONArray("history").size()==0){
                continue;
            }
            int maxDelay = 1000;

            boolean use = true;
            JSONArray delayArray = nodeDelay.getJSONArray("history");
            for (int i1 = 0; i1 < delayArray.size(); i1++) {
                JSONObject itemDelay = delayArray.getJSONObject(i1);
                Integer itemDelayInt = itemDelay.getInt("delay");
                if(itemDelayInt>maxDelay || itemDelayInt==0){
                    use = false;
                    break;
                }
            }
            if(use){
                //System.out.println(itemNodeName);
                validNodeList.add(itemNodeName);
            }
        }
        return validNodeList;
    }

    public static boolean changeRandomNode(){
        List<String> allNode = getAllNode();
        if(CollectionUtil.isEmpty(allNode) || allNode.size()<10){
            log.error("not enough node for change");
            return false;
        }
        String selectNode = RandomUtil.randomEle(allNode);
        HttpRequest request = HttpUtil.createRequest(Method.PUT,clashApiUrl+"/proxies/"+ selectorName);
        request.header("Authorization","Bearer "+secret);
        JSONObject requestBodyObj = new JSONObject();
        requestBodyObj.putOnce("name",selectNode);
        request.body(requestBodyObj.toString());
        HttpResponse response = request.execute();
        if(response.getStatus()==204){
            curNode = selectNode;
            log.info("change node success:{}",selectNode);
            return true;
        }
        log.error("change node error,:{}",response.body());
        return false;
    }

    public static void main(String[] args) {
        changeRandomNode();//自动换节点
    }

}

通过调用changeRandomNode方法完成自动换IP过程。getAllNode方法用于获取所有活跃且低延迟的节点。

正文完