Gogs 1 неделя назад
Родитель
Сommit
e24b415eb2
5 измененных файлов с 47 добавлено и 19 удалено
  1. 8 5
      README.md
  2. 17 0
      config copy.jsonbak2
  3. 2 2
      config.json
  4. 8 8
      config.py
  5. 12 4
      socks_edge.py

+ 8 - 5
README.md

@@ -289,12 +289,13 @@ sudo /home/mynetspeeder/scripts/start-transparent.sh --enable-udp --capture-uid
 
 ```json
 {
-  "udp_redundancy": 1,
-  "udp_direct_redundancy": 2,
-  "udp_direct_redundancy_v4": 2,
-  "udp_direct_redundancy_v6": 2,
+  "udp_redundancy": 2,
+  "udp_direct_redundancy": 3,
+  "udp_direct_redundancy_v4": 3,
+  "udp_direct_redundancy_v6": 3,
   "udp_always_broadcast": true,
-  "udp_copy_interval_ms": 8
+  "udp_copy_interval_ms": 2,
+  "udp_failover_idle_ms": 700
 }
 ```
 
@@ -306,8 +307,10 @@ sudo /home/mynetspeeder/scripts/start-transparent.sh --enable-udp --capture-uid
 - `udp_direct_redundancy_v6`:可单独指定 IPv6 目标的 UDP direct 副本数
 - `udp_always_broadcast`:即使已有 winner,后续包仍持续并发发往所有可用路径
 - `udp_copy_interval_ms`:多副本之间的间隔,单位毫秒
+- `udp_failover_idle_ms`:winner 空闲多久后允许更积极切换,单位毫秒
 
 默认策略更偏向抗丢包和稳态可用,而不是节省流量。
+当前默认值已经向直播、短视频和长视频连续播放场景倾斜,优先降低转圈和短时卡顿,不优先节省流量。
 
 如果你希望同时启用本机显式 SOCKS5 出站入口,只需要在 `config.json` 增加端口:
 

+ 17 - 0
config copy.jsonbak2

@@ -0,0 +1,17 @@
+{
+  "strategy": "top3",
+  "udp_redundancy": 2,
+  "udp_direct_redundancy": 2,
+  "udp_direct_redundancy_v4": 2,
+  "udp_direct_redundancy_v6": 1,
+  "probe_interval": 3,
+  "relay_reconnect_delay": 1,
+  "relay_reconnect_max_delay": 10,
+  "udp_always_broadcast": true,
+  "udp_copy_interval_ms": 0,
+  "udp_failover_idle_ms": 600,
+  "socks_host": "127.0.0.1",
+  "socks_port": 19180,
+  "relays": [
+  ]
+}

+ 2 - 2
config.json

@@ -11,7 +11,7 @@
   "tcp_connect_happy_eyeballs_delay": 0.25,
   "tcp_warmup_bytes": 1024288,
   "tcp_loser_grace_ms": 1000,
-  "udp_redundancy": 1,
+  "udp_redundancy": 2,
   "udp_direct_redundancy": 2,
   "udp_direct_redundancy_v4": 2,
   "udp_direct_redundancy_v6": 1,
@@ -20,7 +20,7 @@
   "relay_reconnect_max_delay": 10,
   "udp_always_broadcast": true,
   "udp_copy_interval_ms": 0,
-  "udp_failover_idle_ms": 1200,
+  "udp_failover_idle_ms": 600,
   "socks_host": "127.0.0.1",
   "socks_port": 19180,
   "relays": [

+ 8 - 8
config.py

@@ -42,13 +42,13 @@ class Config:
     direct_redundancy_v4: int | None = None
     direct_redundancy_v6: int | None = None
     direct_max_redundancy: int = 3
-    udp_redundancy: int = 1
-    udp_direct_redundancy: int = 2
+    udp_redundancy: int = 2
+    udp_direct_redundancy: int = 3
     udp_direct_redundancy_v4: int | None = None
     udp_direct_redundancy_v6: int | None = None
     udp_always_broadcast: bool = True
-    udp_copy_interval_ms: int = 8
-    udp_failover_idle_ms: int = 1200
+    udp_copy_interval_ms: int = 2
+    udp_failover_idle_ms: int = 700
     socks_host: str = "127.0.0.1"
     socks_port: int = 0
 
@@ -79,13 +79,13 @@ class Config:
             direct_redundancy_v4=raw.get("direct_redundancy_v4"),
             direct_redundancy_v6=raw.get("direct_redundancy_v6"),
             direct_max_redundancy=max(1, raw.get("direct_max_redundancy", 3)),
-            udp_redundancy=max(0, raw.get("udp_redundancy", 1)),
-            udp_direct_redundancy=max(1, raw.get("udp_direct_redundancy", 2)),
+            udp_redundancy=max(0, raw.get("udp_redundancy", 2)),
+            udp_direct_redundancy=max(1, raw.get("udp_direct_redundancy", 3)),
             udp_direct_redundancy_v4=raw.get("udp_direct_redundancy_v4"),
             udp_direct_redundancy_v6=raw.get("udp_direct_redundancy_v6"),
             udp_always_broadcast=raw.get("udp_always_broadcast", True),
-            udp_copy_interval_ms=max(0, raw.get("udp_copy_interval_ms", 8)),
-            udp_failover_idle_ms=max(100, raw.get("udp_failover_idle_ms", 1200)),
+            udp_copy_interval_ms=max(0, raw.get("udp_copy_interval_ms", 2)),
+            udp_failover_idle_ms=max(100, raw.get("udp_failover_idle_ms", 700)),
             socks_host=raw.get("socks_host", "127.0.0.1"),
             socks_port=max(0, raw.get("socks_port", 0)),
         )

+ 12 - 4
socks_edge.py

@@ -230,6 +230,10 @@ class UdpAssociateServer(asyncio.DatagramProtocol):
             print(f"[edge] udp associate peer={peer_text}")
         self.associate_peer = peer_text
 
+    def _client_flow_key(self, addr, host: str, port: int) -> tuple[tuple[str, int], str, int]:
+        # Treat port rebinding from the same client IP as the same logical UDP client.
+        return ((addr[0], 0), host, port)
+
     def datagram_received(self, data: bytes, addr) -> None:
         if len(data) < 10:
             return
@@ -237,12 +241,16 @@ class UdpAssociateServer(asyncio.DatagramProtocol):
             self.client_addr = addr
             print(f"[edge] udp client bound addr={addr[0]}:{addr[1]}")
         elif addr != self.client_addr:
-            print(f"[edge] udp client rebound old={self.client_addr[0]}:{self.client_addr[1]} new={addr[0]}:{addr[1]}")
-            self._reset_client_state(addr)
+            if addr[0] == self.client_addr[0]:
+                print(f"[edge] udp client port update host={addr[0]} old_port={self.client_addr[1]} new_port={addr[1]}")
+                self.client_addr = addr
+            else:
+                print(f"[edge] udp client rebound old={self.client_addr[0]}:{self.client_addr[1]} new={addr[0]}:{addr[1]}")
+                self._reset_client_state(addr)
         host, port, payload = self._parse_socks_udp(data)
         loop = asyncio.get_running_loop()
         now = loop.time()
-        flow_key = ((addr[0], addr[1]), host, port)
+        flow_key = self._client_flow_key(addr, host, port)
         flow = self.client_flows.get(flow_key)
         if flow is None:
             flow = UdpFlowState(
@@ -265,7 +273,7 @@ class UdpAssociateServer(asyncio.DatagramProtocol):
         remapped_flows: dict[tuple[tuple[str, int], str, int], UdpFlowState] = {}
         for flow in list(self.client_flows.values()):
             flow.client_addr = (addr[0], addr[1])
-            remapped_flows[((addr[0], addr[1]), flow.target_host, flow.target_port)] = flow
+            remapped_flows[self._client_flow_key(addr, flow.target_host, flow.target_port)] = flow
         self.client_flows = remapped_flows
         self.client_addr = addr
         print(f"[edge] udp client rebound migrated old={old_addr[0]}:{old_addr[1]} new={addr[0]}:{addr[1]} flows={len(self.client_flows)}")