This commit is contained in:
本间白猫 2025-01-07 10:50:13 +08:00
parent 4b4e62ca51
commit 2e83336f97
5 changed files with 103 additions and 20 deletions

View File

@ -51,7 +51,12 @@ async def run_server(server):
clients = set()
server_instance = None
try:
server_instance = await asyncio.start_server(lambda r, w: handle_client_wrapper(server, r, w, clients),'0.0.0.0', int(server.config['port']))
server_instance = await asyncio.start_server(
lambda r, w: handle_client_wrapper(server, r, w, clients),
'0.0.0.0',
int(server.config['port']),
limit=256 * 1024
)
async with server_instance:
await server_instance.serve_forever()
except asyncio.CancelledError:

View File

@ -202,10 +202,15 @@ Through actual testing, when proxy server performance is sufficient, ProxyCat ca
## Change Log
### 2025/01/07
- Added caching mechanism to proxy detection module to prevent frequent checks
- Optimized error handling and logging
### 2025/01/03
- Centralize the management of configuration parameters into configuration files to improve maintenance convenience.
- Fix some known bugs and improve stability and concurrency capabilities.
- Centralized configuration parameters management into config files for better maintenance
- Fixed known bugs and improved stability and concurrency capabilities
### 2025/01/02
@ -221,6 +226,47 @@ Through actual testing, when proxy server performance is sufficient, ProxyCat ca
- Restructured code, split into separate files
- Added automatic proxy switching when current proxy fails during forwarding
### 2024/09/29
- Removed less-used single cycle mode, replaced with custom mode for customizable proxy switching logic
- Changed proxy validity checking to asynchronous for better speed
- Removed problematic SOCKS4 protocol support
- Beautified logging system
- Improved exception handling logic
- Added proxy format validation
### 2024/09/10
- Optimized concurrency efficiency, supporting next request before receiving response
- Added load balancing mode for random proxy selection and concurrent proxy usage
- Changed proxy validity checking to asynchronous for better efficiency
### 2024/09/09
- Added option to validate proxies in ip.txt at startup
- Function downgrade to support lower Python versions
### 2024/09/03
- Added local SOCKS5 listening for wider software compatibility
- Changed some functions to support lower Python versions
- Beautified output display
### 2024/08/31
- Major project structure adjustment
- Beautified display with continuous proxy switch time indication
- Added Ctrl+C support for stopping
- Major adjustment to async requests, improved concurrency efficiency
- Changed from runtime parameters to local ini config file
- Added support for local authentication-free mode
- Added version detection
- Added proxy server authentication
- Added GetIP update only on request feature
- Added proxy protocol auto-detection
- Added HTTPS protocol support
- Changed asyncio.timeout() to asyncio.wait_for() for lower Python version support
[Additional change log entries follow similar pattern...]
## Development Plan

View File

@ -36,17 +36,18 @@
## 功能特点
- **双协议支持**:支持 SOCKS5 和 HTTP 协议监听地址,适配更多工具。
- **多重代理协议**:支持 HTTP/HTTPS/SOCKS5 代理服务器,满足不同应用场景需求。
- **多种切换模式**:按照顺序循环使用代理列表中的每一个代理,确保均衡使用;随机选择可用代理,分摊流量负载,提升性能。允许用户自定义代理选择逻辑,灵活满足特定需求。
- **函数获取代理**:支持通过 GetIP 函数动态获取即时可用的代理,保证代理的实时性和有效性。
- **自动检测有效性**:在启动时自动检测代理的可用性,过滤无效代理,确保代理列表的可靠性。
- **仅在代理转发时切换**:在计时器归零时,有新的请求才会更换为新的代理服务器,防止运行时一直消耗资源。
- **支持代理失效切换**:在转发流量过程中,遇到代理服务器突然失效,可自动切换到新的代理上。
- **代理池身份认证**:支持基于用户名和密码的代理认证和黑白名单机制的代理认证,增强代理的安全性,防止未授权访问。
- **实时状态更新**:显示当前代理状态和下次切换时间,帮助用户了解代理动态。
- **可配置文件**:通过 config.ini 文件轻松调整端口、模式、认证信息等参数,适应不同使用场景。
- **版本检测**:内置版本检测功能,自动检查最新版本并提醒用户更新,确保软件的持续优化。
- **双协议监听**:支持 HTTP/SOCKS5 协议监听,兼容更多工具。
- **三种协议代理地址**:支持 HTTP/HTTPS/SOCKS5 代理服务器,满足不同需求。
- **灵活切换模式**:支持顺序、随机及自定义代理选择,优化流量分配。
- **动态获取代理**:通过 GetIP 函数即时获取可用代理,支持 API 接口调用。
- **代理保护机制**:在使用 GetIP 方式获取代理时,首次运行不会直接请求获取,将会在收到请求的时候才获取。
- **自动代理检测**:启动时自动检测代理有效性,剔除无效代理。
- **智能切换代理**:仅在请求运行时获取新代理,减少资源消耗。
- **失效代理切换**:代理失效后自动验证切换新代理,确保不中断服务。
- **身份认证支持**:支持用户名/密码认证和黑白名单管理,提高安全性。
- **实时状态显示**:展示代理状态和切换时间,实时掌握代理动态。
- **配置灵活**:通过 config.ini 文件自定义端口、模式和认证信息等。
- **版本检测**:自动检查软件更新,保证版本最新。
## 安装与使用
@ -208,6 +209,11 @@ docker logs proxycat-app-1
## 更新日志
### 2025/01/07
- 代理检测模块增加缓存机制,防止频繁检查。
- 优化部分错误处理和日志记录。
### 2025/01/03
- 集中配置参数到配置文件中管理,提升维护便利。

View File

@ -1,4 +1,4 @@
import asyncio, logging, random, httpx, re, os
import asyncio, logging, random, httpx, re, os, time
from configparser import ConfigParser
from packaging import version
from colorama import Fore
@ -270,7 +270,16 @@ def load_ip_list(file_path):
with open(file_path, 'r') as f:
return {line.strip() for line in f if line.strip()}
_proxy_check_cache = {}
_proxy_check_ttl = 10
async def check_proxy(proxy):
current_time = time.time()
if proxy in _proxy_check_cache:
cache_time, is_valid = _proxy_check_cache[proxy]
if current_time - cache_time < _proxy_check_ttl:
return is_valid
proxy_type = proxy.split('://')[0]
check_funcs = {
'http': check_http_proxy,
@ -282,9 +291,12 @@ async def check_proxy(proxy):
return False
try:
return await check_funcs[proxy_type](proxy)
is_valid = await check_funcs[proxy_type](proxy)
_proxy_check_cache[proxy] = (current_time, is_valid)
return is_valid
except Exception as e:
logging.error(f"{proxy_type.upper()}代理 {proxy} 检测失败: {e}")
_proxy_check_cache[proxy] = (current_time, False)
return False
async def check_http_proxy(proxy):

View File

@ -40,7 +40,10 @@ class AsyncProxyServer:
self.proxy_failed = False
self.proxy_fail_count = 0
self.max_fail_count = 2
self.semaphore = asyncio.Semaphore(10000)
self.semaphore = asyncio.Semaphore(20000)
self.buffer_size = 256 * 1024
self.proxy_cache = {}
self.proxy_cache_ttl = 10
async def get_next_proxy(self):
if self.mode == 'load_balance':
@ -240,10 +243,9 @@ class AsyncProxyServer:
async def _pipe(self, reader, writer):
try:
buffer_size = 65536
while True:
try:
data = await asyncio.wait_for(reader.read(buffer_size), timeout=30)
data = await asyncio.wait_for(reader.read(self.buffer_size), timeout=30)
if not data:
break
writer.write(data)
@ -470,7 +472,8 @@ class AsyncProxyServer:
writer.write(b'\r\n')
await writer.drain()
async for chunk in response.aiter_bytes(chunk_size=65536):
chunk_size = 256 * 1024
async for chunk in response.aiter_bytes(chunk_size=chunk_size):
if asyncio.current_task().cancelled():
raise asyncio.CancelledError
writer.write(f'{len(chunk):X}\r\n'.encode('utf-8', errors='ignore'))
@ -515,3 +518,14 @@ class AsyncProxyServer:
await self.get_proxy()
self.last_switch_time = time.time()
logging.info(get_message('proxy_switched', self.language, old_proxy, self.current_proxy))
async def check_proxy(self, proxy):
current_time = time.time()
if proxy in self.proxy_cache:
cache_time, is_valid = self.proxy_cache[proxy]
if current_time - cache_time < self.proxy_cache_ttl:
return is_valid
is_valid = await self._check_proxy_impl(proxy)
self.proxy_cache[proxy] = (current_time, is_valid)
return is_valid