浏览代码

优化一下连续断开,验证优化卡死情况

Gogs 2 周之前
父节点
当前提交
0958e95ecc
共有 4 个文件被更改,包括 40 次插入12 次删除
  1. 2 0
      README.md
  2. 14 5
      config.json
  3. 2 0
      config.py
  4. 22 7
      transparent_edge.py

+ 2 - 0
README.md

@@ -156,6 +156,7 @@ sudo /home/mynetspeeder/scripts/start-transparent.sh --kernel 24 --capture-uid $
   "direct_open_timeout": 6.0,
   "relay_open_timeout": 6.0,
   "tcp_connect_happy_eyeballs_delay": 0.25,
+  "direct_ipv6_enabled": true,
   "relay_reconnect_delay": 3.0,
   "relay_tcp_nodelay": true
 }
@@ -170,6 +171,7 @@ sudo /home/mynetspeeder/scripts/start-transparent.sh --kernel 24 --capture-uid $
 - `direct_max_redundancy`:当某目标或某地址族近期更偏向 relay 胜出时,允许自动放大到的最大 direct 并发数
 - `direct_redundancy_v4`:可单独指定 IPv4 目标的 direct 并发数
 - `direct_redundancy_v6`:可单独指定 IPv6 目标的 direct 并发数
+- `direct_ipv6_enabled`:关闭后,IPv6 目标不再参与 direct 竞选;`false` 时 IPv6 目标会直接失败
 
 示例:
 

+ 14 - 5
config.json

@@ -2,17 +2,26 @@
   "strategy": "top3",
   "redundancy": 3,
   "direct_redundancy": 3,
-  "direct_max_redundancy": 3,
-  "direct_redundancy_v6": 3,
+  "direct_max_redundancy": 4,
+  "direct_redundancy_v4": 3,
+  "direct_redundancy_v6": 2,
+  "direct_ipv6_enabled": true,
 
-  "tcp_warmup_bytes": 2097152,
-  "tcp_loser_grace_ms": 900,
+  "direct_open_timeout": 3.0,
+  "relay_open_timeout": 3.0,
+  "tcp_connect_happy_eyeballs_delay": 0.05,
+  "tcp_warmup_bytes": 131072,
+  "tcp_loser_grace_ms": 300,
 
-  "udp_redundancy":2,
+  "udp_redundancy":1,
   "udp_direct_redundancy": 3,
+  "udp_direct_redundancy_v4": 3,
+  "udp_direct_redundancy_v6": 2,
   "probe_interval": 3,
   "relay_reconnect_delay": 1,
   "relay_reconnect_max_delay": 10,
+  "udp_always_broadcast":true,
+  "udp_copy_interval_ms": 0,
   "socks_host": "127.0.0.1",
   "socks_port": 19180,
   "relays": [

+ 2 - 0
config.py

@@ -30,6 +30,7 @@ class Config:
     direct_open_timeout: float = 10.0
     relay_open_timeout: float = 10.0
     tcp_connect_happy_eyeballs_delay: float | None = None
+    direct_ipv6_enabled: bool = True
     relay_reconnect_delay: float = 3.0
     relay_reconnect_attempts: int = 5
     relay_reconnect_max_delay: float = 30.0
@@ -64,6 +65,7 @@ class Config:
             direct_open_timeout=raw.get("direct_open_timeout", 10.0),
             relay_open_timeout=raw.get("relay_open_timeout", 10.0),
             tcp_connect_happy_eyeballs_delay=raw.get("tcp_connect_happy_eyeballs_delay"),
+            direct_ipv6_enabled=raw.get("direct_ipv6_enabled", True),
             relay_reconnect_delay=raw.get("relay_reconnect_delay", 3.0),
             relay_reconnect_attempts=max(1, raw.get("relay_reconnect_attempts", 5)),
             relay_reconnect_max_delay=max(raw.get("relay_reconnect_delay", 3.0), raw.get("relay_reconnect_max_delay", 30.0)),

+ 22 - 7
transparent_edge.py

@@ -215,6 +215,7 @@ class TransparentSession:
     closed: bool = False
     pump_task: asyncio.Task | None = None
     loser_close_task: asyncio.Task | None = None
+    open_tasks: list[asyncio.Task] = field(default_factory=list)
 
     def _record_win(self, winner: BasePath) -> None:
         self.stats[winner.name] = self.stats.get(winner.name, 0) + 1
@@ -237,8 +238,8 @@ class TransparentSession:
         print(f"[edge] tcp win session={self.session_id} target={self.target.host}:{self.target.port} winner={winner.name} direct={direct_wins} relay={relay_wins} relay_breakdown={relay_detail} target_pref={target_pref} target_direct={target_direct} target_relay={target_relay} target_breakdown={target_detail} family_pref={family_pref} family={family_key} family_direct={family_direct} family_relay={family_relay}")
 
     async def start(self) -> None:
-        await asyncio.gather(*(path.open(self.target) for path in self.paths), return_exceptions=True)
-        await asyncio.wait_for(self.open_event.wait(), timeout=15)
+        self.open_tasks = [asyncio.create_task(path.open(self.target)) for path in self.paths]
+        await asyncio.wait_for(self.open_event.wait(), timeout=8)
         if self.opened_count == 0:
             raise ConnectionError(self.errors[0] if self.errors else "all paths failed")
         self.pump_task = asyncio.create_task(self._pump_local())
@@ -311,7 +312,12 @@ class TransparentSession:
         if self.closed:
             return
         self.closed = True
-        print(f"[edge] session={self.session_id} closed target={self.target.host}:{self.target.port}")
+        if self.errors:
+            detail = ", ".join(self.errors[:3])
+            print(
+                f"[edge] session={self.session_id} closed target={self.target.host}:{self.target.port} "
+                f"errors={len(self.errors)} detail={detail}"
+            )
         if self.pump_task and self.pump_task is not asyncio.current_task():
             self.pump_task.cancel()
             with contextlib.suppress(Exception):
@@ -320,6 +326,13 @@ class TransparentSession:
             self.loser_close_task.cancel()
             with contextlib.suppress(Exception):
                 await self.loser_close_task
+        for task in self.open_tasks:
+            if task is not asyncio.current_task():
+                task.cancel()
+        for task in self.open_tasks:
+            if task is not asyncio.current_task():
+                with contextlib.suppress(Exception):
+                    await task
         await asyncio.gather(*(path.close() for path in self.paths), return_exceptions=True)
         self.writer.close()
         with contextlib.suppress(Exception):
@@ -485,10 +498,6 @@ class UdpFlow:
             self.send_task.cancel()
             with contextlib.suppress(Exception):
                 await self.send_task
-        print(
-            f"[edge] udp flow={self.flow_id} closed target={self.target.host}:{self.target.port} "
-            f"sent={self.packets_sent} received={self.packets_received} dup={self.duplicate_responses}"
-        )
         await asyncio.gather(*(path.close() for path in self.paths), return_exceptions=True)
 
 
@@ -665,6 +674,8 @@ class TransparentEdge:
                 await asyncio.gather(server4.serve_forever(), server6.serve_forever())
 
     def _direct_redundancy_for_target(self, target: TargetAddress) -> int:
+        if target.family == socket.AF_INET6 and not self.config.direct_ipv6_enabled:
+            return 0
         base = self.config.direct_redundancy
         if target.family == socket.AF_INET6 and self.config.direct_redundancy_v6 is not None:
             base = self.config.direct_redundancy_v6
@@ -682,6 +693,8 @@ class TransparentEdge:
 
     def _build_direct_paths(self, session: TransparentSession) -> list[BasePath]:
         count = self._direct_redundancy_for_target(session.target)
+        if count <= 0:
+            return []
         return [
             DirectTcpPath(
                 name=f"direct-{index + 1}" if count > 1 else "direct",
@@ -694,6 +707,8 @@ class TransparentEdge:
         ]
 
     def _build_udp_direct_paths(self, target: TargetAddress, flow_id: int) -> list[BasePath]:
+        if target.family == socket.AF_INET6 and not self.config.direct_ipv6_enabled:
+            return []
         count = max(1, self.config.udp_direct_redundancy)
         if target.family == socket.AF_INET6 and self.config.udp_direct_redundancy_v6 is not None:
             count = max(1, self.config.udp_direct_redundancy_v6)