dpmp 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dpmp-0.1.1/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
dpmp-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,415 @@
1
+ Metadata-Version: 2.4
2
+ Name: dpmp
3
+ Version: 0.1.1
4
+ Summary: DPMP - Dual-Punch Multi-Path Protocol: P2P connectivity & transport library
5
+ Author: DPMP
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/yourname/dpmp
8
+ Keywords: p2p,nat-traversal,hole-punching,multi-path,udp,tcp,peer-to-peer,nat
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.7
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Internet
20
+ Classifier: Topic :: System :: Networking
21
+ Requires-Python: >=3.7
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # DPMP · Dual-Punch Multi-Path Protocol
27
+
28
+ **双打洞多路径协议** —— 一个 P2P 连接与传输底层库。
29
+
30
+ DPMP 只做一件事:**把字节可靠地从 A 送到 B**。
31
+ 你提供「服务器 + 房间号」,它返回「一个可收发 `bytes` 的通道」;
32
+ 至于这些字节是文件、视频帧还是游戏消息 —— 由你的上层定义。
33
+
34
+ 适用场景:文件互传、远程控制、投屏、游戏房间等一切需要 P2P 的软件底座。
35
+
36
+ ---
37
+
38
+ ## 核心能力(两项独创)
39
+
40
+ 1. **双打洞协同(Dual-Punch)**
41
+ 先通过 UDP 打洞建立可靠控制通道(UDP-RTP),再用该通道作为**控制面**
42
+ 协调 TCP 打洞(轮次对齐、候选并行、就绪信号、失败通知)。
43
+ 控制面与数据面分离,显著提升 TCP 打洞成功率。
44
+
45
+ 2. **梯度冗余多路径(Multi-Path)**
46
+ 同一对端维护多条路径,按 **hot / warm_safe / warm_loose** 三级角色分级调度:
47
+ 热备承载数据、保守暖备待命、宽松暖备兜底。热备断线自动接力、换路续传。
48
+
49
+ ---
50
+
51
+ ## 分层架构
52
+
53
+ | 层 | 模块 | 职责 |
54
+ |---|---|---|
55
+ | 协议 | `dpmp.protocol` | 线格式常量与编解码(两端唯一事实来源,不可配) |
56
+ | 连接 | `dpmp.link` | 发现 / 信令 / 双打洞 / UDP-RTP / 路径调度 / 连接管理 |
57
+ | 传输 | `dpmp.stream` | 统一字节流通道(屏蔽 TCP / UDP-RTP 差异) |
58
+ | 配置 | `dpmp.config` | 调优参数(全可配) |
59
+ | 默认 | `dpmp.defaults` | 默认信令服务器(便利入口,可覆盖) |
60
+ | 工具 | `dpmp.util` | 本机 IP / 子网 / 广播地址 / 设备标识 |
61
+
62
+ 依赖:**纯标准库,零第三方**。
63
+
64
+ ---
65
+
66
+ ## 安装
67
+
68
+ ```bash
69
+ pip install -e .
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 快速开始
75
+
76
+ ### 1. 公网模式(异地互传)
77
+
78
+ ```python
79
+ from dpmp.link.signaling import SignalingClient
80
+ from dpmp.link.manager import LinkManager
81
+
82
+ # ① 信令客户端(不传服务器则用内置默认;见「默认服务器」一节)
83
+ sig = SignalingClient(
84
+ servers=["your.server.com:3336", "backup.com:3336"], # 多服务器故障转移
85
+ room="my_room", # 房间号,两端填同一个
86
+ name="my_pc", # 显示名
87
+ tcp_port=9998, # 本机打洞 / 长连接端口
88
+ lan_ips=[], # 本机局域网 IP(可空)
89
+ device_id="dev-001", # 稳定设备标识(去重用)
90
+ punch_local_port=9998, # 打洞本地端口
91
+ udp_hole_port=9996, # UDP 打洞端口
92
+ )
93
+
94
+ # ② 连接管理(打洞 + 多路径 + 保活)
95
+ lm = LinkManager(sig, local_tcp_port=9998)
96
+
97
+ # ③ 把信令事件接到连接管理(必须)
98
+ sig.on_joined = lm.on_joined
99
+ sig.on_member_join = lm.on_member_join
100
+ sig.on_member_leave = lm.on_member_leave
101
+ sig.on_punch_go = lm.on_punch_go
102
+ sig.on_udp_hole_ready = lm.on_udp_hole_ready
103
+ sig.on_mapping_ready = lm.mark_mapping_ready
104
+
105
+ # ④ 连接就绪回调 —— 在这里跑你自己的协议
106
+ def on_ready(peer_id, sock, member):
107
+ sock.sendall(b"hello") # 发
108
+ data = sock.recv(4096) # 收
109
+ lm.on_socket_ready = on_ready
110
+
111
+ # ⑤ 启动
112
+ lm.start()
113
+ sig.start() # 依次尝试 servers,第一个成功即停
114
+
115
+ # ⑥ 网络切换时重建(宿主检测到后调用,见「网络切换重建」一节)
116
+ # 示例:Android 在 NetworkCallback 里、桌面在 IP 轮询里调用
117
+ def on_network_changed():
118
+ lm.on_network_changed() # 关闭旧连接 + 信令重绑 + 重新打洞(复用身份)
119
+ ```
120
+
121
+ ### 2. 局域网模式(**无需服务器**)
122
+
123
+ ```python
124
+ from dpmp.link.discovery import Discovery
125
+
126
+ d = Discovery(
127
+ device_id="dev-001", hostname="my-pc",
128
+ on_new_node=lambda ip, msg: print("发现设备", ip),
129
+ )
130
+ d.start()
131
+ d.broadcast_search() # 广播搜索
132
+ d.scan_subnet("192.168.1.0/24") # 扫描子网
133
+ print(d.get_nodes()) # {ip: {hostname, device_id, mac, ...}}
134
+ ```
135
+
136
+ ### 3. 主动发送(按路径角色选路)
137
+
138
+ ```python
139
+ ch = lm.get_send_channel(peer_id) # 返回 (sock, io_lock, is_udp, role) 或 None
140
+ if ch:
141
+ sock, lock, is_udp, role = ch # role: hot / warm_safe / warm_loose
142
+ with lock:
143
+ sock.sendall(b"data")
144
+ ```
145
+
146
+ ### 4. 单独使用打洞
147
+
148
+ ```python
149
+ from dpmp.link.puncher import HolePuncher
150
+
151
+ p = HolePuncher(local_tcp_port=9998)
152
+ p.set_udp_hint(peer_id, ip, udp_port) # 双打洞:用 UDP 端口预测 TCP 候选
153
+ result = p.punch(peer, at_ms) # 并行打洞,返回 PunchResult(含 sock)
154
+ ```
155
+
156
+ ### 5. 网络切换重建(接口反转)
157
+
158
+ DPMP 平台无关,**由宿主检测网络变化**,检测到后调用一行:
159
+
160
+ ```python
161
+ # 宿主:检测到 Wi-Fi/蜂窝切换、IP 变化时调用
162
+ lm.on_network_changed()
163
+ ```
164
+
165
+ DPMP 内部自动完成:关闭旧连接 → 信令重开并重新加入(复用旧 id,无感重建)
166
+ → 对所有成员重新打洞。带 10 秒冷却。
167
+
168
+ 宿主检测示例(平台相关):
169
+ ```python
170
+ # Android:ConnectivityManager.NetworkCallback.onAvailable 里
171
+ # 桌面:定时轮询本机 IP 集合,发现变化时
172
+ # 只要最终调用 lm.on_network_changed() 即可
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 服务器地址
178
+
179
+ ### 三种写法
180
+
181
+ ```python
182
+ # 写法一:IP + 端口
183
+ SignalingClient(server_ip="1.2.3.4", server_port=3336, ...)
184
+
185
+ # 写法二:多服务器列表(第一个失败自动切下一个)
186
+ SignalingClient(servers=[
187
+ "primary.example.com:3336",
188
+ "backup1.example.com:3336",
189
+ ("backup2.example.com", 3336, 3337, 3338), # ip, port, tcp_port, nat_port
190
+ ], auto_failover=True, ...)
191
+
192
+ # 写法三:字典
193
+ SignalingClient(servers=[{"ip": "1.2.3.4", "port": 3336}], ...)
194
+ ```
195
+
196
+ ### 默认服务器(便利入口,非依赖)
197
+
198
+ 不传任何服务器时,回退到内置默认服务器,方便开箱即用:
199
+
200
+ ```python
201
+ from dpmp import DEFAULT_SERVER, DEFAULT_SERVER_EXPIRES, check_default_server_expiry
202
+
203
+ print(DEFAULT_SERVER) # "42.194.133.132"
204
+ print(DEFAULT_SERVER_EXPIRES) # "2026-11-01"
205
+ print(check_default_server_expiry())
206
+ # {'status': 'ok', 'days_left': 38, 'expires': '2026-11-01'}
207
+ ```
208
+
209
+ 默认服务器**只是便利**,不是依赖:
210
+
211
+ - 使用默认服务器时,`start()` 会自动检查到期并在临近/过期时提示;
212
+ - 传了自己的 `server_ip` / `servers` 后,默认服务器**完全被绕过**;
213
+ - **局域网模式根本不使用服务器**。
214
+
215
+ > ⚠️ 默认服务器到期后,请改用自建服务器或备用服务器。
216
+ > 修改默认值见 `dpmp/defaults.py`。
217
+
218
+ ---
219
+
220
+ ## 配置
221
+
222
+ 调优参数通过 `Config` 按实例配置(协议常量不可配):
223
+
224
+ ```python
225
+ from dpmp import Config
226
+
227
+ cfg = Config(
228
+ rtp_window_init=64, # UDP-RTP 自适应窗口初始值
229
+ rtp_window_min=1, # 自适应窗口下限
230
+ rtp_window_max=256, # 自适应窗口上限(AIMD 动态调节)
231
+ rtp_keepalive_interval=10, # 保活间隔
232
+ punch_retry=5, # 打洞重试次数
233
+ punch_connect_timeout=4.0, # 打洞连接超时
234
+ punch_concurrency=8, # 打洞并发任务数
235
+ punch_candidate_concurrency=2,# 单次打洞中【并发 connect 的候选数】上限
236
+ heartbeat_interval=20, # 信令心跳间隔
237
+ proto_floor={"tcp": 30, "udp": 15}, # 保活硬性下限
238
+ rebuild_cooldown_sec=30.0, # 重建冷却
239
+ )
240
+ sig = SignalingClient(..., config=cfg)
241
+ lm = LinkManager(sig, 9998, config=cfg)
242
+
243
+ # 或改全局默认
244
+ import dpmp
245
+ dpmp.DEFAULT_CONFIG.rtp_window = 200
246
+ ```
247
+
248
+ **分层原则**:
249
+ - **协议常量不可配**(改了与对端不兼容)
250
+ - **调优参数、地址端口全部可配**
251
+
252
+ ---
253
+
254
+ ## 自建服务器
255
+
256
+ 信令服务器**独立开源**(见项目 `服务器/信令服务器.py`),
257
+ 只牵线、不传数据、带宽近乎为零。可自行部署:
258
+
259
+ - Linux:`install_linux.sh`(systemd)
260
+ - Windows:`install_windows.bat`(计划任务)
261
+ - 配置:`config.json`(端口、房间上限、心跳超时等)
262
+
263
+ 服务器地址通过 `server_ip` / `servers` 传给 `SignalingClient`,
264
+ 客户端**不写死任何服务器**。
265
+
266
+ ---
267
+
268
+ ## API 参考
269
+
270
+ ### 顶层(`import dpmp`)
271
+
272
+ | 名称 | 说明 |
273
+ |---|---|
274
+ | `Config` / `DEFAULT_CONFIG` | 调优参数 |
275
+ | `DEFAULT_SERVER` / `DEFAULT_SERVER_EXPIRES` | 默认服务器与到期日 |
276
+ | `default_servers()` | 默认服务器候选列表 |
277
+ | `check_default_server_expiry()` | 检查默认服务器到期状态 |
278
+ | `__version__` / `__protocol__` | 版本 / 协议标识 |
279
+
280
+ ### 连接层(`dpmp.link`)
281
+
282
+ | 名称 | 说明 |
283
+ |---|---|
284
+ | `Discovery` | 局域网 UDP 发现(广播 / 扫描 / 心跳) |
285
+ | `SignalingClient` | 公网信令客户端(房间 / 校时 / 映射观测 / NAT 探测) |
286
+ | `HolePuncher` / `PunchResult` | 双打洞核心 / 打洞结果 |
287
+ | `UdpReliableSocket` | UDP 可靠通道(UDP-RTP) |
288
+ | `PeerPathScheduler` / `Path` / `KeepaliveScheduler` | 梯度冗余多路径调度 |
289
+ | `LinkManager` / `Conn` | 连接管理 / 单条连接 |
290
+
291
+ ### 传输层(`dpmp.stream`)
292
+
293
+ | 名称 | 说明 |
294
+ |---|---|
295
+ | `Channel` | 统一字节流通道(`sendall` / `recv` / `recv_exact` / `close`) |
296
+ | `wrap_channel(sock, io_lock, role)` | 包装底层 socket |
297
+ | `is_udp_rtp(sock)` | 判断是否 UDP-RTP 通道 |
298
+
299
+ ### 工具层(`dpmp.util.net`)
300
+
301
+ | 名称 | 说明 |
302
+ |---|---|
303
+ | `get_all_local_ips(ipv6=False)` | 本机所有 IP |
304
+ | `get_all_subnets()` | 本机所有子网 CIDR |
305
+ | `get_broadcast_addrs()` | 广播地址 |
306
+ | `get_subnet_for_ip(ip)` | 由 IP 推断子网 |
307
+ | `get_mac_address()` | 本机 MAC |
308
+ | `get_or_create_device_id(path)` | 持久化设备 UUID |
309
+
310
+ ---
311
+
312
+ ## 关键回调与方法
313
+
314
+ ### LinkManager 回调
315
+
316
+ | 回调 | 触发时机 |
317
+ |---|---|
318
+ | `on_socket_ready(peer_id, sock, member)` | TCP 通道建立(**最常用**) |
319
+ | `on_udp_ready(peer_id, rtp)` | UDP-RTP 通道建立 |
320
+ | `on_state_changed()` | 成员状态变化(刷新 UI) |
321
+
322
+ ### LinkManager 方法
323
+
324
+ | 方法 | 用途 |
325
+ |---|---|
326
+ | `get_send_channel(peer_id, exclude_socks=None)` | 按角色选路,返回可发送通道 |
327
+ | `get_socket(peer_id)` | 取 TCP socket |
328
+ | `get_udp_socket(peer_id)` | 取 UDP-RTP 通道 |
329
+ | `get_members()` | 成员列表(含状态、路径角色) |
330
+ | `get_path_roles(peer_id)` | 各路径角色 |
331
+ | `mark_active(peer_id)` | 标记活跃(重置空闲降频) |
332
+ | `on_network_changed()` | **网络切换时由宿主调用**,重建所有连接(见下节) |
333
+ | `start()` / `stop()` | 启动 / 停止 |
334
+
335
+ ---
336
+
337
+ ## 网络切换重建(接口反转)
338
+
339
+ 网络切换(Wi-Fi ↔ 蜂窝、IP 变化)后,旧网络上的所有 socket 与 NAT 映射全部失效。
340
+ DPMP 是**平台无关**的库,无法自己感知网络变化,因此采用「接口反转」:
341
+
342
+ - **宿主应用负责【检测】**(平台相关:Android NetworkCallback、桌面 IP 轮询等)
343
+ - **DPMP 负责【重建】**(统一逻辑,所有用户受益)
344
+
345
+ 宿主检测到网络变化后,只需一行调用:
346
+
347
+ ```python
348
+ lm.on_network_changed()
349
+ ```
350
+
351
+ DPMP 内部编排完整重建:
352
+
353
+ 1. 关闭所有现存连接(旧 NAT 映射已失效)
354
+ 2. 让信令客户端**重开 socket 并重新加入**(`SignalingClient.rebind()`)
355
+ 3. 对所有成员**重新发起打洞**
356
+
357
+ **无感重建**:重建时
358
+ - 不发 BYE(服务器保留成员条目,对端不掉线)
359
+ - 携带旧 `my_id`(`reuse_id`)——服务器支持则**复用身份**,对端看到的是
360
+ 「同一成员回归」;旧服务器忽略该字段,退化为生成新 id(等价重新 join)
361
+
362
+ 带 10 秒冷却,避免网络抖动频繁重建。
363
+
364
+ ---
365
+
366
+ ## 端口说明
367
+
368
+ | 端口 | 协议 | 用途 |
369
+ |---|---|---|
370
+ | 3336 | UDP | 信令服务器(加入房间 / 心跳 / 打洞协调) |
371
+ | 3337 | TCP | 信令服务器 TCP 映射观测 |
372
+ | 3338 | UDP | 信令服务器 NAT 类型探测 |
373
+ | 9996 | UDP | 房间模式 UDP 打洞 |
374
+ | 9998 | TCP | 房间模式打洞 / 长连接 |
375
+ | 9997 | UDP | 局域网主动扫描 |
376
+ | 9998 | UDP | 局域网设备发现(广播 / 心跳) |
377
+ | 9999 | TCP | 局域网文件传输 |
378
+
379
+ 所有端口均可通过参数或 `Config` 覆盖。
380
+
381
+ ---
382
+
383
+ ## 协议文档
384
+
385
+ - `DPMP_PROTOCOL.md` —— 完整协议规范(两端实现唯一事实来源)
386
+ - `test_vectors.json` —— 协议测试向量(防 Python / Kotlin 两端漂移)
387
+
388
+ ---
389
+
390
+ ## 版本历史
391
+
392
+ ### 0.1.1(底层能力补强)
393
+
394
+ - **新增**:UDP-RTP 自适应窗口(AIMD)——发送端按 ACK 加性增、按超时乘性减,
395
+ 在 1~256 之间动态调节;高延迟链路上吞吐上限提升数倍。
396
+ - **新增**:打洞候选并发限制(`punch_candidate_concurrency`,默认 2)——
397
+ 降低同一本地端口上 SO_REUSEPORT 的入站 SYN 匹配冲突。
398
+ - **新增**:网络切换重建(接口反转)——`SignalingClient.rebind()` +
399
+ `LinkManager.on_network_changed()`;宿主检测网络变化,DPMP 统一重建。
400
+ - **新增**:身份复用(`reuse_id`)——重建时复用旧 my_id,实现无感重建。
401
+ - **修复**:收到对端 PUNCH_FAIL 时未关闭半开连接——该 socket 可能被
402
+ `get_send_channel` 选为发送通道,把数据发进单向死连接。现在无条件关闭并
403
+ 触发路径轮转。
404
+
405
+ ### 0.1.0(初版)
406
+
407
+ - 双打洞协同、UDP-RTP 可靠通道、梯度冗余多路径、局域网发现、公网信令。
408
+
409
+ ---
410
+
411
+ ## 许可证
412
+
413
+ 本项目采用 **Apache License 2.0** 开源许可,详见 `LICENSE` 文件。
414
+
415
+ 你可以自由使用、修改、分发本项目(含商业用途),需保留版权声明与许可声明。