Bladeren bron

feat: update

jerry 2 maanden geleden
bovenliggende
commit
4c9d80d347
3 gewijzigde bestanden met toevoegingen van 156 en 384 verwijderingen
  1. 15 15
      config/groups.json
  2. 49 297
      config/proxies.json
  3. 92 72
      toolkit/proxy_tunnel.py

+ 15 - 15
config/groups.json

@@ -6,7 +6,7 @@
         "need_account": true,
         "local_account_pool": "ie_nl",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -63,7 +63,7 @@
         "need_account": true,
         "local_account_pool": "sg_fr",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -120,7 +120,7 @@
         "need_account": true,
         "local_account_pool": "au_fr",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -193,7 +193,7 @@
         "need_account": true,
         "local_account_pool": "gb_it",
         "need_proxy": true,
-        "proxy_pool": "iproyal-gb",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -266,7 +266,7 @@
         "need_account": true,
         "local_account_pool": "gb_nl",
         "need_proxy": true,
-        "proxy_pool": "iproyal-gb",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -339,7 +339,7 @@
         "need_account": true,
         "local_account_pool": "gb_no",
         "need_proxy": true,
-        "proxy_pool": "iproyal-gb",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -396,7 +396,7 @@
         "need_account": true,
         "local_account_pool": "ie_at",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -453,7 +453,7 @@
         "need_account": true,
         "local_account_pool": "ie_dk",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -510,7 +510,7 @@
         "need_account": true,
         "local_account_pool": "ie_fi",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -567,7 +567,7 @@
         "need_account": true,
         "local_account_pool": "ie_hu",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -624,7 +624,7 @@
         "need_account": true,
         "local_account_pool": "ie_is",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 180,
@@ -734,7 +734,7 @@
         "need_account": true,
         "local_account_pool": "gb_es",
         "need_proxy": true,
-        "proxy_pool": "iproyal-gb",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
@@ -783,11 +783,11 @@
     {
         "identifier": "TLS_GB_FR",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "gb_fr",
         "need_proxy": true,
-        "proxy_pool": "iproyal-gb",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
@@ -923,7 +923,7 @@
         "need_account": true,
         "local_account_pool": "ie_gr",
         "need_proxy": true,
-        "proxy_pool": "isp_proxy",
+        "proxy_pool": "iproyal",
         "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 1,

+ 49 - 297
config/proxies.json

@@ -1,253 +1,103 @@
 {
-    "oxylabs": [
-        {
-            "id": 100003,
-            "ip": "disp.oxylabs.io",
-            "password": "jYubEsw6~g3z1Uh",
-            "port": 8001,
-            "scheme": "http",
-            "username": "user-visafly_zFNdf"
-        },
-        {
-            "id": 100004,
-            "ip": "disp.oxylabs.io",
-            "password": "jYubEsw6~g3z1Uh",
-            "port": 8002,
-            "scheme": "http",
-            "username": "user-visafly_zFNdf"
-        }
-    ],
-    "isp_proxy": [
-        {
-            "id": 100001,
-            "ip": "95.135.130.175",
-            "password": "hmuROCk1FDebCnL",
-            "port": 46247,
-            "scheme": "http",
-            "username": "GB6o2vBrXFjz4ya"
-        },
-        {
-            "id": 100002,
-            "ip": "95.135.130.29",
-            "password": "WmqFTSvRvtxChIT",
-            "port": 43740,
-            "scheme": "http",
-            "username": "JUcjydi0HKZzWC6"
-        },
-        {
-            "id": 100003,
-            "ip": "95.135.130.105",
-            "password": "a9udkCOGYZKGkLS",
-            "port": 47342,
-            "scheme": "http",
-            "username": "1mtj2c6xoLfrOLm"
-        },
-        {
-            "id": 100004,
-            "ip": "95.135.130.157",
-            "password": "q1UNK1gmiQdxJ1g",
-            "port": 42290,
-            "scheme": "http",
-            "username": "alxuf86deeI898d"
-        },
-        {
-            "id": 100005,
-            "ip": "95.135.130.167",
-            "password": "bmKmauMV5CuOCrh",
-            "port": 48333,
-            "scheme": "http",
-            "username": "gPaIdSyKsp2TnQ1"
-        },
-        {
-            "id": 100006,
-            "ip": "95.135.130.181",
-            "password": "0HU9RGLRTNNwecf",
-            "port": 46253,
-            "scheme": "http",
-            "username": "XpSiGAiz3zwAyi1"
-        },
-        {
-            "id": 100007,
-            "ip": "95.135.130.192",
-            "password": "anYmNO4luxcm22m",
-            "port": 41255,
-            "scheme": "http",
-            "username": "xRGDPswifGmmbog"
-        },
-        {
-            "id": 100008,
-            "ip": "95.135.130.203",
-            "password": "qXEZWLa74q8Awdx",
-            "port": 49012,
-            "scheme": "http",
-            "username": "jHATN4mVM6kcltO"
-        },
-        {
-            "id": 100009,
-            "ip": "95.135.130.206",
-            "password": "MnL8pmNAdpLo0h7",
-            "port": 47504,
-            "scheme": "http",
-            "username": "aLoTyl9YbSvdxbD"
-        },
-        {
-            "id": 100010,
-            "ip": "95.135.130.33",
-            "password": "slxIVWHqzZpkSPY",
-            "port": 44720,
-            "scheme": "http",
-            "username": "EnnPVteJalQvk7E"
-        },
-        {
-            "id": 100011,
-            "ip": "95.135.130.53",
-            "password": "5fS8EMqdto9JnO9",
-            "port": 44764,
-            "scheme": "http",
-            "username": "QeLVYhf0Pbz5BEe"
-        },
-        {
-            "id": 100012,
-            "ip": "95.135.130.66",
-            "password": "4HzLag9JYiPTZ5J",
-            "port": 46470,
-            "scheme": "http",
-            "username": "c1zHamB7LAOeNdb"
-        },
+    "iproyal": [
         {
             "id": 100021,
-            "ip": "89.33.195.129",
-            "password": "d160bc0854",
+            "ip": "195.178.151.14",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100022,
-            "ip": "89.33.195.64",
-            "password": "d160bc0854",
+            "ip": "195.178.151.20",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100023,
-            "ip": "89.33.195.93",
-            "password": "d160bc0854",
+            "ip": "195.178.151.134",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100024,
-            "ip": "89.33.195.42",
-            "password": "d160bc0854",
+            "ip": "195.178.151.187",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100025,
-            "ip": "95.170.29.126",
-            "password": "d160bc0854",
+            "ip": "165.254.9.248",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100026,
-            "ip": "91.193.255.166",
-            "password": "d160bc0854",
+            "ip": "165.254.9.156",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100027,
-            "ip": "91.193.255.60",
-            "password": "d160bc0854",
+            "ip": "109.72.116.223",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100028,
-            "ip": "91.193.255.210",
-            "password": "d160bc0854",
+            "ip": "109.72.116.124",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100029,
-            "ip": "91.193.255.149",
-            "password": "d160bc0854",
+            "ip": "109.72.116.184",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae212b29a2a"
+            "username": "14a7fe11fea49"
         },
         {
             "id": 100030,
-            "ip": "91.193.255.245",
-            "password": "d160bc0854",
-            "port": 12323,
-            "scheme": "http",
-            "username": "14ae212b29a2a"
-        }
-    ],
-    "iproyal-gb": [
-        {
-            "id": 1,
-            "ip": "91.236.217.55",
+            "ip": "89.33.195.58",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae6e75feb01",
-            "password": "6952ea93f8"
+            "username": "14a7fe11fea49"
         },
         {
-            "id": 2,
-            "ip": "91.236.216.188",
+            "id": 100031,
+            "ip": "89.33.195.43",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae6e75feb01",
-            "password": "6952ea93f8"
+            "username": "14a7fe11fea49"
         },
         {
-            "id": 3,
-            "ip": "91.236.217.206",
+            "id": 100032,
+            "ip": "95.170.29.68",
+            "password": "919e0ee7ee",
             "port": 12323,
             "scheme": "http",
-            "username": "14ae6e75feb01",
-            "password": "6952ea93f8"
+            "username": "14a7fe11fea49"
         },
         {
-            "id": 4,
-            "ip": "91.236.217.133",
-            "port": 12323,
-            "scheme": "http",
-            "username": "14ae6e75feb01",
-            "password": "6952ea93f8"
-        },
-        {
-            "id": 5,
-            "ip": "185.54.14.49",
-            "port": 12323,
-            "scheme": "http",
-            "username": "14ae6e75feb01",
-            "password": "6952ea93f8"
-        },
-        {
-            "id": 6,
-            "ip": "192.177.31.137",
-            "port": 12323,
-            "scheme": "http",
-            "username": "14ae6e75feb01",
-            "password": "6952ea93f8"
-        }
-    ],
-    "iproyal": [
-        {
-            "id": 100021,
+            "id": 100033,
             "ip": "89.33.195.129",
             "password": "d160bc0854",
             "port": 12323,
@@ -255,7 +105,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100022,
+            "id": 100034,
             "ip": "89.33.195.64",
             "password": "d160bc0854",
             "port": 12323,
@@ -263,7 +113,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100023,
+            "id": 100035,
             "ip": "89.33.195.93",
             "password": "d160bc0854",
             "port": 12323,
@@ -271,7 +121,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100024,
+            "id": 100036,
             "ip": "89.33.195.42",
             "password": "d160bc0854",
             "port": 12323,
@@ -279,7 +129,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100025,
+            "id": 100037,
             "ip": "95.170.29.126",
             "password": "d160bc0854",
             "port": 12323,
@@ -287,7 +137,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100026,
+            "id": 100038,
             "ip": "91.193.255.166",
             "password": "d160bc0854",
             "port": 12323,
@@ -295,7 +145,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100027,
+            "id": 100039,
             "ip": "91.193.255.60",
             "password": "d160bc0854",
             "port": 12323,
@@ -303,7 +153,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100028,
+            "id": 100040,
             "ip": "91.193.255.210",
             "password": "d160bc0854",
             "port": 12323,
@@ -311,7 +161,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100029,
+            "id": 100041,
             "ip": "91.193.255.149",
             "password": "d160bc0854",
             "port": 12323,
@@ -319,7 +169,7 @@
             "username": "14ae212b29a2a"
         },
         {
-            "id": 100030,
+            "id": 100042,
             "ip": "91.193.255.245",
             "password": "d160bc0854",
             "port": 12323,
@@ -327,104 +177,6 @@
             "username": "14ae212b29a2a"
         }
     ],
-    "proxy_cheap": [
-        {
-            "id": 100001,
-            "ip": "95.135.130.175",
-            "password": "hmuROCk1FDebCnL",
-            "port": 46247,
-            "scheme": "http",
-            "username": "GB6o2vBrXFjz4ya"
-        },
-        {
-            "id": 100002,
-            "ip": "95.135.130.29",
-            "password": "WmqFTSvRvtxChIT",
-            "port": 43740,
-            "scheme": "http",
-            "username": "JUcjydi0HKZzWC6"
-        },
-        {
-            "id": 100003,
-            "ip": "95.135.130.105",
-            "password": "a9udkCOGYZKGkLS",
-            "port": 47342,
-            "scheme": "http",
-            "username": "1mtj2c6xoLfrOLm"
-        },
-        {
-            "id": 100004,
-            "ip": "95.135.130.157",
-            "password": "q1UNK1gmiQdxJ1g",
-            "port": 42290,
-            "scheme": "http",
-            "username": "alxuf86deeI898d"
-        },
-        {
-            "id": 100005,
-            "ip": "95.135.130.167",
-            "password": "bmKmauMV5CuOCrh",
-            "port": 48333,
-            "scheme": "http",
-            "username": "gPaIdSyKsp2TnQ1"
-        },
-        {
-            "id": 100006,
-            "ip": "95.135.130.181",
-            "password": "0HU9RGLRTNNwecf",
-            "port": 46253,
-            "scheme": "http",
-            "username": "XpSiGAiz3zwAyi1"
-        },
-        {
-            "id": 100007,
-            "ip": "95.135.130.192",
-            "password": "anYmNO4luxcm22m",
-            "port": 41255,
-            "scheme": "http",
-            "username": "xRGDPswifGmmbog"
-        },
-        {
-            "id": 100008,
-            "ip": "95.135.130.203",
-            "password": "qXEZWLa74q8Awdx",
-            "port": 49012,
-            "scheme": "http",
-            "username": "jHATN4mVM6kcltO"
-        },
-        {
-            "id": 100009,
-            "ip": "95.135.130.206",
-            "password": "MnL8pmNAdpLo0h7",
-            "port": 47504,
-            "scheme": "http",
-            "username": "aLoTyl9YbSvdxbD"
-        },
-        {
-            "id": 100010,
-            "ip": "95.135.130.33",
-            "password": "slxIVWHqzZpkSPY",
-            "port": 44720,
-            "scheme": "http",
-            "username": "EnnPVteJalQvk7E"
-        },
-        {
-            "id": 100011,
-            "ip": "95.135.130.53",
-            "password": "5fS8EMqdto9JnO9",
-            "port": 44764,
-            "scheme": "http",
-            "username": "QeLVYhf0Pbz5BEe"
-        },
-        {
-            "id": 100012,
-            "ip": "95.135.130.66",
-            "password": "4HzLag9JYiPTZ5J",
-            "port": 46470,
-            "scheme": "http",
-            "username": "c1zHamB7LAOeNdb"
-        }
-    ],
     "local": [
         {
             "id": 100029,

+ 92 - 72
toolkit/proxy_tunnel.py

@@ -6,9 +6,10 @@ import time
 
 class ProxyTunnel:
     """
-    【轻量级版】管理本地代理隧道
-    不依赖 mitmproxy,使用纯 Socket 实现 TCP 盲转发和 Header 注入。
-    资源占用极低,启动速度快,无子进程僵死风险。
+    【修复优化版】管理本地代理隧道
+    1. 启用 TCP_NODELAY 消除握手延迟 (关键修复)
+    2. 开启 KeepAlive 防止链路中断
+    3. 修复非阻塞模式下 sendall 导致的数据丢失问题
     """
     def __init__(self, upstream_ip, upstream_port, username, password):
         self.upstream_ip = upstream_ip
@@ -16,7 +17,7 @@ class ProxyTunnel:
         self.username = username
         self.password = password
         
-        # 预先计算 Proxy-Authorization 头,避免运行时计算
+        # 预先计算 Proxy-Authorization 头
         auth_str = f"{username}:{password}"
         b64_auth = base64.b64encode(auth_str.encode()).decode()
         self.auth_header = f"Proxy-Authorization: Basic {b64_auth}\r\n"
@@ -27,150 +28,169 @@ class ProxyTunnel:
         self.listen_thread = None
 
     def start(self):
-        """启动本地监听,返回 '127.0.0.1:port'"""
         try:
             self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
             
-            # 绑定到随机空闲端口
             self.server_socket.bind(('127.0.0.1', 0))
             self.local_port = self.server_socket.getsockname()[1]
-            self.server_socket.listen(100) # 允许一定的并发连接
+            self.server_socket.listen(128) # 增加连接队列长度
             
             self.running = True
             
-            # 启动后台线程处理连接请求
             self.listen_thread = threading.Thread(target=self._accept_loop, daemon=True)
             self.listen_thread.start()
             
-            # Socket 绑定成功即代表启动成功,无需等待
             return f"127.0.0.1:{self.local_port}"
         except Exception as e:
             self.stop()
-            raise RuntimeError(f"Failed to start lightweight tunnel: {e}")
+            raise RuntimeError(f"Failed to start tunnel: {e}")
 
     def stop(self):
-        """停止服务"""
         self.running = False
         if self.server_socket:
             try:
-                # 关闭 Socket 会触发 accept 抛出 OSError,从而结束 _accept_loop
                 self.server_socket.close()
             except Exception:
                 pass
         self.server_socket = None
 
     def _accept_loop(self):
-        """循环接收浏览器的连接"""
         while self.running:
             try:
-                # 设置超时以便能响应 stop 信号
                 if self.server_socket:
-                    self.server_socket.settimeout(1.0)
-                    try:
-                        client_sock, _ = self.server_socket.accept()
-                    except socket.timeout:
-                        continue
-                    except OSError:
-                        # Socket 关闭时触发
-                        break
-                    
-                    # 为每个连接启动一个线程进行转发
-                    t = threading.Thread(target=self._handle_client, args=(client_sock,), daemon=True)
-                    t.start()
-                else:
-                    break
+                    # 使用 select 替代 settimeout,减少 CPU 空转
+                    r, _, _ = select.select([self.server_socket], [], [], 1.0)
+                    if r:
+                        try:
+                            client_sock, _ = self.server_socket.accept()
+                            t = threading.Thread(target=self._handle_client, args=(client_sock,), daemon=True)
+                            t.start()
+                        except OSError:
+                            break
             except Exception:
-                break
+                continue
+
+    def _optimize_socket(self, sock):
+        """核心优化:设置 Socket 选项"""
+        try:
+            # 1. 禁用 Nagle 算法:数据包立即发送,不等待填满缓冲区
+            # 这是解决 "HttpClient Timeout" 的关键
+            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+            
+            # 2. 开启 KeepAlive:防止防火墙切断空闲连接
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
+            
+            # 3. 增大缓冲区 (Linux/Mac 可选,Windows 一般自动管理)
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32*1024)
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 32*1024)
+        except Exception:
+            pass
 
     def _handle_client(self, client_sock):
-        """处理单个连接:注入 Header -> 双向转发"""
         upstream_sock = None
         try:
-            client_sock.settimeout(30) # 防止半开连接
+            self._optimize_socket(client_sock)
+            client_sock.settimeout(30) 
             
-            # 1. 读取浏览器发来的第一个包 (通常是 CONNECT 或 GET)
-            first_packet = client_sock.recv(16384)
+            # 1. 读取首包 (32KB 缓冲区)
+            try:
+                first_packet = client_sock.recv(32768)
+            except socket.timeout:
+                return # 客户端连上但不发数据
+                
             if not first_packet:
-                client_sock.close()
                 return
 
-            # 2. 连接远程代理
+            # 2. 连接上游
             upstream_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            upstream_sock.settimeout(10) # 连接超时
+            self._optimize_socket(upstream_sock) # 同样优化上游 Socket
+            
+            upstream_sock.settimeout(10) # 连接超时 10s
             upstream_sock.connect((self.upstream_ip, self.upstream_port))
             
-            # 3. [关键步骤] 在第一个包中注入 Proxy-Authorization
+            # 连接建立后,将超时设为 None (阻塞模式),交由 select 控制
+            upstream_sock.settimeout(None)
+            client_sock.settimeout(None)
+            
+            # 3. 注入 Header
             sep = b'\r\n'
             idx = first_packet.find(sep)
             if idx != -1:
-                # 插入 Auth 头
                 new_packet = first_packet[:idx+2] + self.auth_header.encode() + first_packet[idx+2:]
             else:
-                new_packet = first_packet # 异常情况直接透传
+                new_packet = first_packet
 
-            # 4. 发送修改后的包给远程代理
+            # 4. 发送首包 (阻塞式发送,保证数据完整)
             upstream_sock.sendall(new_packet)
             
-            # 5. 进入双向转发模式 (Tunneling)
+            # 5. 双向转发
             self._pipe_sockets(client_sock, upstream_sock)
 
         except Exception:
             pass
         finally:
-            # 显式拆分 try-except 以避免语法解析错误
-            if client_sock:
-                try:
-                    client_sock.close()
-                except Exception:
-                    pass
-            if upstream_sock:
-                try:
-                    upstream_sock.close()
-                except Exception:
-                    pass
+            self._close_socket(client_sock)
+            self._close_socket(upstream_sock)
 
     def _pipe_sockets(self, sock1, sock2):
-        """高效的双向数据转发"""
+        """
+        修复后的转发逻辑:
+        保持 Socket 为阻塞模式,利用 select 监听可读状态。
+        """
         sockets = [sock1, sock2]
-        try:
-            sock1.setblocking(0)
-            sock2.setblocking(0)
-        except Exception:
-            return
-        
         last_activity = time.time()
-        IDLE_TIMEOUT = 60 # 60秒无数据传输则断开
+        IDLE_TIMEOUT = 120 # 延长空闲超时
         
         while self.running:
             try:
-                # 使用 select 监听可读状态
+                # 监听可读事件
                 r, _, x = select.select(sockets, [], sockets, 1.0)
                 
-                if x: 
-                    break # 发生错误
+                if x: break # Socket 异常
                 
                 if not r:
-                    # 空闲检查
                     if time.time() - last_activity > IDLE_TIMEOUT:
                         break
                     continue
                 
                 for s in r:
                     try:
-                        data = s.recv(65536) # 64KB buffer
-                        if not data:
-                            return # 连接关闭
-                        
-                        # 转发给对方
-                        target = sock2 if s is sock1 else sock1
+                        # 尝试读取
+                        data = s.recv(32768)
+                    except ConnectionResetError:
+                        data = None
+                    
+                    if not data:
+                        return # 连接关闭
+                    
+                    # 确定发送目标
+                    target = sock2 if s is sock1 else sock1
+                    
+                    # 关键修改:使用阻塞式 sendall
+                    # 如果网络卡顿,线程会在这里暂停等待,而不是抛出错误或丢包
+                    try:
                         target.sendall(data)
-                        last_activity = time.time()
-                    except Exception:
+                    except BrokenPipeError:
                         return
+                        
+                    last_activity = time.time()
                     
             except Exception:
                 break
 
+    def _close_socket(self, sock):
+        """优雅关闭 Socket"""
+        if sock:
+            try:
+                # 发送 FIN 包,通知对端数据发送完毕
+                sock.shutdown(socket.SHUT_RDWR)
+            except Exception:
+                pass
+            try:
+                sock.close()
+            except Exception:
+                pass
+
     def __del__(self):
         self.stop()