mnet 0.1.4 → 0.1.6
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.
- checksums.yaml +4 -4
- data/README.en.md +5 -0
- data/README.md +5 -0
- data/lib/mnet/version.rb +1 -1
- data/lib/mnet.rb +28 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0fbab81dc8d236bf99365375204d8a88fddc69bdd739873c9a911257db6da0a
|
|
4
|
+
data.tar.gz: 55bda39f9f15c785493da5938b8c1489dd624a28da79469276cae8460422854c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73998b8ba73cf9d787d41576c578f44183c3f3c5365d8131d8af3912cc688cb06812dc0dae1298e2b993e3ea521c9748dc0152f50e52bcfed8377299c2683ca7
|
|
7
|
+
data.tar.gz: ec19fe682e1672d3948df00c8ea5ebb7222fac2d3527daa81ad6d48f5fc6a142cfcbdf7f621a063d49b9a1ebf930d3b10a9c42bb25cec02a246a1ce28b0b5f6b
|
data/README.en.md
CHANGED
|
@@ -51,6 +51,11 @@ puts sess.readpartial(1024)
|
|
|
51
51
|
| `:mnet` | pure-Ruby ARQ, no C dependency, simple and easy to debug |
|
|
52
52
|
| `:kcp` | C engine (via the `kcp` gem), ~8x faster, requires building a native extension |
|
|
53
53
|
|
|
54
|
+
> With `proto: :kcp`, mnet automatically sizes the KCP engine's MTU to
|
|
55
|
+
> `IP_MTU(1280) - Mnet header(41) - GCM overhead(28, only when a key is used)`, so the full
|
|
56
|
+
> datagram (Mnet header + KCP packet [+ encryption]) stays within the link MTU and is never
|
|
57
|
+
> IP-fragmented. Override it with the `kcp_mtu:` option if needed.
|
|
58
|
+
|
|
54
59
|
## Encryption (pre-shared key)
|
|
55
60
|
|
|
56
61
|
Per-packet AES-256-GCM; both ends must pre-share the same 32-byte key:
|
data/README.md
CHANGED
|
@@ -49,6 +49,11 @@ puts sess.readpartial(1024)
|
|
|
49
49
|
| `:mnet` | 纯 Ruby ARQ,无 C 依赖,简单、易调试 |
|
|
50
50
|
| `:kcp` | C 引擎(依赖 `kcp` gem),快约 8 倍,需编译原生扩展 |
|
|
51
51
|
|
|
52
|
+
> `proto: :kcp` 时,mnet 会自动把 KCP 引擎的 MTU 设为
|
|
53
|
+
> `IP_MTU(1280) - Mnet 头(41) - 加密开销(28,仅启用 key 时)`,
|
|
54
|
+
> 使「Mnet 头 + KCP 包(+ 加密)」整包不超过链路 MTU,避免 IP 分片。
|
|
55
|
+
> 如需自定义可用 `kcp_mtu:` 选项覆盖。
|
|
56
|
+
|
|
52
57
|
## 加密(预共享密钥)
|
|
53
58
|
|
|
54
59
|
每包 AES-256-GCM,两端需预共享同一个 32 字节密钥:
|
data/lib/mnet/version.rb
CHANGED
data/lib/mnet.rb
CHANGED
|
@@ -35,6 +35,9 @@ module Mnet
|
|
|
35
35
|
# IP(20) + UDP(8) + our header + GCM tag(16) leaves ~1190 for a segment.
|
|
36
36
|
DEFAULT_MSS = 1200
|
|
37
37
|
|
|
38
|
+
# AES-256-GCM 每包的额外开销:12 字节 nonce + 16 字节认证标签。
|
|
39
|
+
GCM_OVERHEAD = 28
|
|
40
|
+
|
|
38
41
|
# RTO bounds (mosh: MIN_RTO = 50ms, MAX_RTO = 1000ms).
|
|
39
42
|
MIN_RTO = 0.05
|
|
40
43
|
MAX_RTO = 1.0
|
|
@@ -59,6 +62,10 @@ module Mnet
|
|
|
59
62
|
FLAG_MIGRATE = 0x01
|
|
60
63
|
FLAG_KCP = 0x02 # session uses the KCP (C) engine instead of the Ruby ARQ
|
|
61
64
|
|
|
65
|
+
# KCP 接收窗口(ikcp.c 内 IKCP_WND_RCV,固定 128)。单次 ikcp_send 超过
|
|
66
|
+
# 窗口大小的分段数会返回 -2 丢弃,故 KcpSession#write 按此切块。
|
|
67
|
+
KCP_WND_RCV = 128
|
|
68
|
+
|
|
62
69
|
HEADER_LEN = MAGIC_LEN + SESSION_ID_LEN + 8 + 8 + 1 + 1 + 4
|
|
63
70
|
|
|
64
71
|
MAX_RETRIES = 10
|
|
@@ -108,6 +115,13 @@ module Mnet
|
|
|
108
115
|
OpenSSL::Digest::SHA256.digest(key)[0, SESSION_ID_LEN]
|
|
109
116
|
end
|
|
110
117
|
|
|
118
|
+
# KCP 引擎的 MTU。每个 KCP 包会被整体包进 Mnet 头(HEADER_LEN)再作为单个
|
|
119
|
+
# UDP 数据报发送,加密时还要再叠加 GCM 开销,因此 KCP 自身的 MTU 必须为这些
|
|
120
|
+
# 开销留出空间,保证整包 <= IP_MTU,避免 IP 分片(移动网络/VPN 下分片极易丢)。
|
|
121
|
+
def kcp_mtu(key = nil)
|
|
122
|
+
IP_MTU - HEADER_LEN - (key ? GCM_OVERHEAD : 0)
|
|
123
|
+
end
|
|
124
|
+
|
|
111
125
|
# A connected stream socket pair, portable across Windows/Linux/macOS.
|
|
112
126
|
# Prefers a UNIX socketpair; falls back to a loopback TCP pair where AF_UNIX
|
|
113
127
|
# socketpair is unavailable (Windows).
|
|
@@ -681,10 +695,7 @@ module Mnet
|
|
|
681
695
|
|
|
682
696
|
@conv = id.unpack1("N") # KCP conv derived from the session id
|
|
683
697
|
@engine = Kcp::Engine.new(@conv)
|
|
684
|
-
|
|
685
|
-
# 按 IP_MTU(1280) 反推,KCP 包最多 1280 - 42 - 28 = 1210,留点余量取 1200,
|
|
686
|
-
# 保证「KCP 包 + 封装」不超路径 MTU,避免被 IP 分片(分片常被 NAT/防火墙丢)。
|
|
687
|
-
@engine.mtu = 1200
|
|
698
|
+
@engine.setmtu(opts.fetch(:kcp_mtu, Mnet.kcp_mtu(@key)))
|
|
688
699
|
|
|
689
700
|
@m = Monitor.new
|
|
690
701
|
@cv = @m.new_cond
|
|
@@ -719,10 +730,21 @@ module Mnet
|
|
|
719
730
|
data = data.to_s.b
|
|
720
731
|
return 0 if data.empty?
|
|
721
732
|
|
|
733
|
+
total = data.bytesize
|
|
722
734
|
@m.synchronize do
|
|
723
735
|
return 0 if @closed || @eof
|
|
724
|
-
|
|
725
|
-
|
|
736
|
+
|
|
737
|
+
# ikcp_send 单次最多接受 IKCP_WND_RCV(128) 个分段,超出会返回 -2 把整块
|
|
738
|
+
# 数据静默丢弃。这里按 (mss * (窗口-1)) 切块喂入,避免大块写被丢。
|
|
739
|
+
chunk = @engine.mss * (KCP_WND_RCV - 1)
|
|
740
|
+
offset = 0
|
|
741
|
+
while offset < total
|
|
742
|
+
n = [chunk, total - offset].min
|
|
743
|
+
queued = @engine.send(data.byteslice(offset, n))
|
|
744
|
+
break if queued <= 0
|
|
745
|
+
offset += queued
|
|
746
|
+
pump_output
|
|
747
|
+
end
|
|
726
748
|
end
|
|
727
749
|
# 窗口满(有积压)时让出 GVL,避免写线程紧循环饿死处理 ACK 的传输线程。
|
|
728
750
|
Thread.pass if @engine.waitsnd > 0
|