├── .gitignore ├── README.md ├── config.json ├── go.mod ├── go.sum └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go template 2 | # If you prefer the allow list template instead of the deny list, see community template: 3 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 4 | # 5 | # Binaries for programs and plugins 6 | *.exe 7 | *.exe~ 8 | *.dll 9 | *.so 10 | *.dylib 11 | 12 | # Test binary, built with `go test -c` 13 | *.test 14 | 15 | # Output of the go coverage tool, specifically when used with LiteIDE 16 | *.out 17 | 18 | # Dependency directories (remove the comment below to include it) 19 | # vendor/ 20 | 21 | # Go workspace file 22 | go.work 23 | 24 | .idea/ 25 | 26 | *.log 27 | 28 | *.sh -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProxyServer 2 | 3 | 将API代理构建成隧道代理池 4 | 5 |
6 | 7 | ## 介绍 8 | 此项目用于将API代理构建成隧道代理池,即通过一个IP和端口来自动随机取出代理池中的代理。 9 | 10 | API代理即: 11 | * 通过API来获取代理,返回值是代理列表包含1~n个代理 12 | * 例如:`[{"ip":"xxx.xxx.xxx.xxx","port":xx},{"ip":"xxx.xxx.xxx.xxx","port":xx}]` 13 | 14 | 这样的代理不方便利用,在代码中通常需要二次操作,这个项目便能完美解决这个问题。 15 | 16 |
17 | 18 | ## 安装 19 | 1.克隆本项目 20 | ```bash 21 | git clone https://github.com/ThinkerWen/ProxyServer.git 22 | ``` 23 | 2.修改`main.go`文件中的`getProxies()`函数,将它改为您的API代理的获取函数即可。(项目中的示例使用的是[小象代理](https://www.xiaoxiangdaili.com/) 24 | 25 | ```bash 26 | go get ProxyServer # 下载依赖项 27 | go build ProxyServer # 编译可执行程序 28 | ./ProxyServer # 运行 29 | ``` 30 | 31 |
32 | 33 | ## 使用 34 | 在后台启动本项目后,只需配置代理地址为`127.0.0.1:12315`即可(在[配置文件](#配置文件)中可修改),以下用Python做示例: 35 | ```python 36 | import requests 37 | 38 | proxies = { 39 | "http": "http://127.0.0.1:12315", 40 | "https": "http://127.0.0.1:12315" 41 | } 42 | requests.get("http://example.com", proxies=proxies) 43 | ``` 44 | 45 |
46 | 47 | ## 配置文件 48 | 配置文件一般默认即可 49 | ```json 50 | { 51 | "bind_ip": "", # 代理服务绑定IP 52 | "bind_port": 12315, # 代理服务绑定端口 53 | "proxy_max_retry": 10, # 代理IP重试次数(超过后此次请求废弃) 54 | "proxy_expire_time": 50, # 代理IP过期时间(超过后此IP移除代理池) 55 | "proxy_pool_length": 50, # 代理IP池大小 56 | "proxy_connect_time_out": 1, # 代理IP连接超时时间(超过后此IP移除代理池) 57 | "check_proxy_time_period": 10, # 代理IP有效性检测间隔 58 | "refresh_proxy_time_period": 10 # API代理的获取间隔 59 | } 60 | ``` -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bind_ip": "", 3 | "bind_port": 12315, 4 | "proxy_max_retry": 10, 5 | "proxy_expire_time": 50, 6 | "proxy_pool_length": 50, 7 | "proxy_connect_time_out": 1, 8 | "check_proxy_time_period": 10, 9 | "refresh_proxy_time_period": 10 10 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module ProxyServer 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThinkerWen/ProxyServer/381aee4756328184c8685bca07eb24036a24cead/go.sum -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "log" 8 | "math/rand" 9 | "net" 10 | "net/http" 11 | "os" 12 | "strconv" 13 | "strings" 14 | "sync" 15 | "time" 16 | ) 17 | 18 | var ( 19 | config Config 20 | mu sync.Mutex 21 | proxyList []string 22 | freeIndex chan int 23 | ProxyApiUrl = "https://api.xiaoxiangdaili.com/ip/get?appKey=956913709144756224&appSecret=eTDUzAY1&cnt=1&wt=json" 24 | ) 25 | 26 | type Config struct { 27 | BindIP string `json:"bind_ip"` 28 | BindPort int `json:"bind_port"` 29 | ProxyMaxRetry int `json:"proxy_max_retry"` 30 | ProxyExpireTime int64 `json:"proxy_expire_time"` 31 | ProxyPoolLength int `json:"proxy_pool_length"` 32 | ProxyConnectTimeOut int `json:"proxy_connect_time_out"` 33 | CheckProxyTimePeriod int `json:"check_proxy_time_period"` 34 | RefreshProxyTimePeriod int `json:"refresh_proxy_time_period"` 35 | } 36 | 37 | func init() { 38 | jsonBytes, err := os.ReadFile("config.json") 39 | if err != nil { 40 | log.Fatal("Error reading JSON file:", err) 41 | } 42 | if err = json.Unmarshal(jsonBytes, &config); err != nil { 43 | log.Fatal("Error decoding JSON:", err) 44 | } 45 | proxyList = make([]string, config.ProxyPoolLength) 46 | freeIndex = make(chan int, config.ProxyPoolLength) 47 | log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 48 | } 49 | 50 | func checkProxy(proxy string) bool { 51 | proxyParts := strings.Split(proxy, ":") 52 | 53 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", proxyParts[0], proxyParts[1]), time.Second*time.Duration(config.ProxyConnectTimeOut)) 54 | if err != nil { 55 | return false 56 | } 57 | defer func(conn net.Conn) { _ = conn.Close() }(conn) 58 | return true 59 | } 60 | 61 | func setProxyList(pl []string) { 62 | if len(pl) == 0 { 63 | return 64 | } 65 | for _, proxy := range pl { 66 | select { 67 | case index := <-freeIndex: 68 | log.Printf("add proxy %v\n", proxy) 69 | proxyList[index] = fmt.Sprintf("%s#%d", proxy, time.Now().Unix()+config.ProxyExpireTime) 70 | case <-time.NewTimer(time.Microsecond * 500).C: 71 | log.Println("Proxy is full") 72 | return 73 | } 74 | } 75 | } 76 | 77 | func getProxies() { 78 | if len(freeIndex) == 0 { 79 | return 80 | } 81 | 82 | response, err := http.Get(ProxyApiUrl) 83 | if err != nil { 84 | return 85 | } 86 | defer func(Body io.ReadCloser) { _ = Body.Close() }(response.Body) 87 | body, err := io.ReadAll(response.Body) 88 | if err != nil { 89 | return 90 | } 91 | var mapResult map[string]interface{} 92 | if err = json.Unmarshal(body, &mapResult); err != nil { 93 | log.Printf("JsonToMapDemo err: %v\n", err) 94 | return 95 | } 96 | if int(mapResult["code"].(float64)) == 200 { 97 | result := mapResult["data"] 98 | proxies := make([]string, 0) 99 | for _, proxyDict := range result.([]interface{}) { 100 | proxy := proxyDict.(map[string]interface{}) 101 | proxies = append(proxies, fmt.Sprintf("%s:%d", proxy["ip"].(string), int(proxy["port"].(float64)))) 102 | } 103 | setProxyList(proxies) 104 | } 105 | } 106 | 107 | func getRandomProxy() string { 108 | for i := 0; i < 10; i++ { 109 | if proxy := proxyList[rand.Intn(config.ProxyPoolLength)]; proxy != "" { 110 | return strings.Split(proxy, "#")[0] 111 | } 112 | } 113 | for _, proxy := range proxyList { 114 | if proxy != "" { 115 | return strings.Split(proxy, "#")[0] 116 | } 117 | } 118 | return "" 119 | } 120 | 121 | func forward(conn net.Conn, remote string, retry int) { 122 | client, err := net.DialTimeout("tcp", remote, time.Second*time.Duration(config.ProxyConnectTimeOut)) 123 | if err != nil { 124 | retry-- 125 | log.Printf("Dial failed: %v", err) 126 | if retry > 0 { 127 | forward(conn, getRandomProxy(), retry) 128 | } 129 | return 130 | } 131 | log.Printf("Forwarding from %v to %v\n", conn.LocalAddr(), client.RemoteAddr()) 132 | 133 | ioCopy := func(src net.Conn, dst net.Conn) { 134 | _, _ = io.Copy(src, dst) 135 | _ = src.Close() 136 | } 137 | go ioCopy(conn, client) 138 | go ioCopy(client, conn) 139 | } 140 | 141 | func checkProxyList() { 142 | log.Printf("代理检测中,代理池容量: %d\n", len(proxyList)-len(freeIndex)) 143 | for i := 0; i < len(proxyList) && proxyList[i] != ""; i++ { 144 | go func(index int) { 145 | proxy := strings.Split(proxyList[index], "#")[0] 146 | period := strings.Split(proxyList[index], "#")[1] 147 | if period >= strconv.FormatInt(time.Now().Unix(), 10) || checkProxy(proxy) { 148 | mu.Lock() 149 | defer mu.Unlock() 150 | log.Printf("remove inactive proxy %s", proxy) 151 | proxyList[index] = "" 152 | freeIndex <- index 153 | } 154 | }(i) 155 | } 156 | time.Sleep(time.Second * time.Duration(config.CheckProxyTimePeriod)) 157 | checkProxyList() 158 | } 159 | 160 | func main() { 161 | for i := 0; i < config.ProxyPoolLength; i++ { 162 | freeIndex <- i 163 | } 164 | 165 | go checkProxyList() 166 | go func() { 167 | for { 168 | getProxies() 169 | time.Sleep(time.Duration(config.RefreshProxyTimePeriod) * time.Second) 170 | } 171 | }() 172 | 173 | listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.BindIP, config.BindPort)) 174 | if err != nil { 175 | log.Fatalf("Failed to setup listener: %v", err) 176 | } 177 | 178 | for { 179 | conn, err := listener.Accept() 180 | if err != nil { 181 | log.Fatalf("ERROR: failed to accept listener: %v", err) 182 | } 183 | log.Printf("Accepted connection from %v\n", conn.RemoteAddr().String()) 184 | px := getRandomProxy() 185 | if px == "" { 186 | px = "127.0.0.1:60001" 187 | } 188 | go forward(conn, px, config.ProxyMaxRetry) 189 | } 190 | } 191 | --------------------------------------------------------------------------------