kcp 0.1.1 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7802d290ec502e834ab5f7eb1e9b4c7a4f664b677ecae6c6f001fce6be4cd3c
4
- data.tar.gz: 58fc1060c2be20897078deb312bfd4e671a5d5dd72b9656205ee2ccf8cc6fa31
3
+ metadata.gz: 571fb1bfe2f3a42c16c77b3c1e1bfe560d2cddf3f103bb74bd8c70cde474507e
4
+ data.tar.gz: 61968bb59630ea85f5d55c294e6cfa72e6f73c57c3ff734a02368239334c5f98
5
5
  SHA512:
6
- metadata.gz: f01a77107b1821d1c32818c403982799e5a97b0dd214d6f9b8cb7e6419f1eb597849d31456f76abecadb75317d2a1a29bd85f3ea8694d88dcf57e2c6699d12d7
7
- data.tar.gz: 2261acc0d59efcb3b94267a0b523e24fa9b036aa5ba7e18f52a2a857194051a94c1a2004d4ba1a993b7141e76e7ca9bfcae828ee7098c91aaaba66e2382b7edc
6
+ metadata.gz: d0972c1a441962ed5ea19c34c1b68575068743c28b6ba18fdf97bd7b98fbaa36a9b03e3000ca505ffc711431fef5ee0596770bb940920eb5b6aa38973f789e75
7
+ data.tar.gz: e984ff6afc0199d36b55b9e91509c3d08b7fe98e7a0da3b2e37124e4a835577a652bcd62c3e91d269b22800c649fd9c7b0aa7019695ff5101a425126282505fc
data/README.en.md CHANGED
@@ -91,11 +91,32 @@ engine.flush
91
91
  pkt = engine.output
92
92
  ```
93
93
 
94
+ ### `setmtu(mtu)`
95
+
96
+ Set the maximum size of a single KCP packet (`mtu`), default 1300. When an upper layer wraps each
97
+ KCP packet in its own header and sends it as one UDP datagram, set this to "link MTU − upper-layer
98
+ header overhead", otherwise the full datagram exceeds the MTU and gets IP-fragmented (fragments are
99
+ frequently dropped on mobile/VPN links).
100
+
101
+ ```ruby
102
+ engine.setmtu(1200) # keep KCP packet + upper-layer header <= link MTU
103
+ ```
104
+
105
+ ### `mss`
106
+
107
+ Returns the current segment payload size (`= mtu - 24` bytes of KCP header). A single `send` accepts
108
+ at most `IKCP_WND_RCV` (128) segments; beyond that it returns `-2` and drops the whole block, so
109
+ upper layers should feed data in `mss * 127` chunks to avoid large writes being dropped.
110
+
111
+ ```ruby
112
+ engine.mss # => 1176 (after setmtu(1200))
113
+ ```
114
+
94
115
  ### `output`
95
116
 
96
- Pull pending encoded packets (a concatenated byte segment, ready for UDP `send`). Returns `nil` when
97
- there is nothing to send. **The pulled bytes must be sent verbatim to the peer**, which feeds them
98
- back via `input`.
117
+ Pull pending encoded packets, **one packet per call** (never larger than `mtu`), ready for UDP `send`.
118
+ Returns `nil` when there is nothing to send. **The pulled bytes must be sent verbatim to the peer**,
119
+ which feeds them back via `input`.
99
120
 
100
121
  ```ruby
101
122
  while (pkt = engine.output)
@@ -229,6 +250,8 @@ end
229
250
  interactive workloads.
230
251
  4. KCP uses a 32-bit millisecond timestamp that wraps every ~49 days; this is expected (the protocol
231
252
  handles the wraparound).
253
+ 5. The default `mtu` is 1300; when an upper layer adds its own header, use `setmtu` to shrink KCP
254
+ packets below the link MTU, so the full datagram is not IP-fragmented.
232
255
 
233
256
  ## License
234
257
 
data/README.md CHANGED
@@ -89,10 +89,29 @@ engine.flush
89
89
  pkt = engine.output
90
90
  ```
91
91
 
92
+ ### `setmtu(mtu)`
93
+
94
+ 设置单个 KCP 包的最大尺寸(mtu),默认 1300。当上层把每个 KCP 包再套一层头作为单个 UDP
95
+ 数据报发送时,应把它设为「链路 MTU - 上层头开销」,否则整包会超过 MTU 触发 IP 分片
96
+ (移动网络/VPN 下分片极易被丢弃)。
97
+
98
+ ```ruby
99
+ engine.setmtu(1200) # 让 KCP 包 + 上层头 <= 链路 MTU
100
+ ```
101
+
102
+ ### `mss`
103
+
104
+ 返回当前分段载荷大小(= `mtu - 24` 字节 KCP 头)。单次 `send` 最多接受 `IKCP_WND_RCV`(128)
105
+ 个分段,超出会返回 `-2` 丢弃;上层按 `mss * 127` 切块喂入可避免大块写被丢。
106
+
107
+ ```ruby
108
+ engine.mss # => 1176(setmtu(1200) 之后)
109
+ ```
110
+
92
111
  ### `output`
93
112
 
94
- 取出待发送的编码包(可能是一段拼接好的字节,直接交给 UDP `send`)。没有待发送数据时返回 `nil`。
95
- **取出的字节必须原样发给对端**,对端收到后原样 `input`。
113
+ 取出待发送的编码包,**每次一个**(不超过 `mtu`),直接交给 UDP `send`。没有待发送数据时
114
+ 返回 `nil`。**取出的字节必须原样发给对端**,对端收到后原样 `input`。
96
115
 
97
116
  ```ruby
98
117
  while (pkt = engine.output)
@@ -215,6 +234,8 @@ end
215
234
  2. `conv` 两端必须一致;并发连接请用不同 `conv`(或在上层协议里用会话 ID 复用)。
216
235
  3. `flush` 是立即刷出(低延迟);`update` 是按间隔节流(省 CPU)。高频交互场景两者配合使用。
217
236
  4. KCP 使用 32 位毫秒时间戳,约 49 天回绕一次,属正常现象(协议内部处理了回绕)。
237
+ 5. 默认 `mtu` 为 1300;上层再包一层头时请用 `setmtu` 把 KCP 包缩小到链路 MTU 以内,避免整包
238
+ 超过 MTU 被 IP 分片。
218
239
 
219
240
  ## 许可
220
241
 
data/ext/kcp/ikcp.c CHANGED
@@ -34,7 +34,7 @@ const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK
34
34
  const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS
35
35
  const IUINT32 IKCP_WND_SND = 32;
36
36
  const IUINT32 IKCP_WND_RCV = 128; // must >= max fragment size
37
- const IUINT32 IKCP_MTU_DEF = 1400;
37
+ const IUINT32 IKCP_MTU_DEF = 1300;
38
38
  const IUINT32 IKCP_ACK_FAST = 3;
39
39
  const IUINT32 IKCP_INTERVAL = 100;
40
40
  const IUINT32 IKCP_OVERHEAD = 24;
data/ext/kcp/kcp_native.c CHANGED
@@ -8,45 +8,46 @@
8
8
  #include <stdlib.h>
9
9
  #include <string.h>
10
10
 
11
- typedef struct {
12
- char *data;
11
+ /* One encoded KCP packet produced by ikcp_flush, kept as its own buffer so a
12
+ single output() call returns exactly one packet. mnet wraps each packet in
13
+ its own header and sends it as one UDP datagram, so packets must never be
14
+ merged: merging would create datagrams larger than the MTU and cause IP
15
+ fragmentation (which is unreliable on mobile/VPN links). */
16
+ typedef struct kcp_pkt {
17
+ struct kcp_pkt *next;
13
18
  int len;
19
+ char data[1];
14
20
  } kcp_pkt;
15
21
 
16
22
  typedef struct {
17
23
  ikcpcb *kcp;
18
- kcp_pkt *pkts;
19
- int count;
20
- int cap;
24
+ kcp_pkt *head;
25
+ kcp_pkt *tail;
21
26
  } kcp_ctx;
22
27
 
23
- /* shim_output 每个 KCP 报文(≤ mtu)单独入队,output() 一次只取一个包,
24
- 避免把多个 KCP 报文拼成一个大 blob,导致上层封成单个超大 UDP 数据报被
25
- IP 分片(分片常被 NAT/防火墙丢弃,造成远端云主机连接异常)。 */
26
28
  static int shim_output(const char *buf, int len, ikcpcb *kcp, void *user) {
27
29
  kcp_ctx *ctx = (kcp_ctx *)user;
28
- if (ctx->count >= ctx->cap) {
29
- int newcap = ctx->cap ? ctx->cap * 2 : 32;
30
- kcp_pkt *npkts = (kcp_pkt *)realloc(ctx->pkts, newcap * sizeof(kcp_pkt));
31
- if (!npkts) return -1;
32
- ctx->pkts = npkts;
33
- ctx->cap = newcap;
34
- }
35
- kcp_pkt *p = &ctx->pkts[ctx->count];
36
- p->data = (char *)malloc(len);
37
- if (!p->data) return -1;
38
- memcpy(p->data, buf, len);
39
- p->len = len;
40
- ctx->count++;
30
+ kcp_pkt *pkt = (kcp_pkt *)malloc(sizeof(kcp_pkt) + len);
31
+ if (!pkt) return -1;
32
+ pkt->next = NULL;
33
+ pkt->len = len;
34
+ memcpy(pkt->data, buf, len);
35
+ if (ctx->tail) ctx->tail->next = pkt; else ctx->head = pkt;
36
+ ctx->tail = pkt;
41
37
  return 0;
42
38
  }
43
39
 
44
40
  static void ctx_free(void *ptr) {
45
41
  kcp_ctx *ctx = (kcp_ctx *)ptr;
46
42
  if (ctx) {
43
+ kcp_pkt *pkt;
47
44
  if (ctx->kcp) ikcp_release(ctx->kcp);
48
- for (int i = 0; i < ctx->count; i++) free(ctx->pkts[i].data);
49
- free(ctx->pkts);
45
+ pkt = ctx->head;
46
+ while (pkt) {
47
+ kcp_pkt *next = pkt->next;
48
+ free(pkt);
49
+ pkt = next;
50
+ }
50
51
  free(ctx);
51
52
  }
52
53
  }
@@ -120,15 +121,15 @@ static VALUE m_kcp_flush(VALUE mod, VALUE self) {
120
121
 
121
122
  static VALUE m_kcp_output(VALUE mod, VALUE self) {
122
123
  kcp_ctx *ctx = get_ctx(self);
123
- if (ctx->count <= 0) return Qnil;
124
- /* 一次只返回一个 KCP 报文(≤ mtu),避免上层拼成超长 UDP 数据报触发 IP 分片 */
125
- kcp_pkt p = ctx->pkts[0];
126
- VALUE buf = rb_str_new(p.data, p.len);
127
- free(p.data);
128
- ctx->count--;
129
- if (ctx->count > 0) {
130
- memmove(&ctx->pkts[0], &ctx->pkts[1], ctx->count * sizeof(kcp_pkt));
131
- }
124
+ kcp_pkt *pkt;
125
+ VALUE buf;
126
+ if (!ctx->head) return Qnil;
127
+ /* 一次只返回一个 KCP 包,交由上层各自封装成不超过 MTU 的 UDP 数据报。 */
128
+ pkt = ctx->head;
129
+ ctx->head = pkt->next;
130
+ if (!ctx->head) ctx->tail = NULL;
131
+ buf = rb_str_new(pkt->data, pkt->len);
132
+ free(pkt);
132
133
  return buf;
133
134
  }
134
135
 
@@ -137,6 +138,11 @@ static VALUE m_kcp_setmtu(VALUE mod, VALUE self, VALUE mtu) {
137
138
  return INT2NUM(ikcp_setmtu(ctx->kcp, NUM2INT(mtu)));
138
139
  }
139
140
 
141
+ static VALUE m_kcp_mss(VALUE mod, VALUE self) {
142
+ kcp_ctx *ctx = get_ctx(self);
143
+ return INT2NUM(ctx->kcp->mss);
144
+ }
145
+
140
146
  static VALUE m_kcp_waitsnd(VALUE mod, VALUE self) {
141
147
  kcp_ctx *ctx = get_ctx(self);
142
148
  return INT2NUM(ikcp_waitsnd(ctx->kcp));
@@ -152,5 +158,6 @@ void Init_kcp_native(void) {
152
158
  rb_define_singleton_method(m, "kcp_flush", m_kcp_flush, 1);
153
159
  rb_define_singleton_method(m, "kcp_output", m_kcp_output, 1);
154
160
  rb_define_singleton_method(m, "kcp_setmtu", m_kcp_setmtu, 2);
161
+ rb_define_singleton_method(m, "kcp_mss", m_kcp_mss, 1);
155
162
  rb_define_singleton_method(m, "kcp_waitsnd", m_kcp_waitsnd, 1);
156
163
  }
data/lib/kcp/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kcp
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.3'
5
5
  end
data/lib/kcp.rb CHANGED
@@ -52,17 +52,24 @@ module Kcp
52
52
  KcpNative.kcp_flush(@ctx)
53
53
  end
54
54
 
55
+ # 设置 KCP 包的最大尺寸(mtu)。默认 1300。上层(如 mnet)把每个 KCP 包
56
+ # 再包一层头作为单个 UDP 数据报发送时,应把它设成「链路 MTU - 上层头开销」,
57
+ # 否则整包会超过 MTU 触发 IP 分片。
58
+ def setmtu(mtu)
59
+ KcpNative.kcp_setmtu(@ctx, mtu)
60
+ end
61
+
62
+ # 当前分段载荷大小(= mtu - 24 字节 KCP 头)。单次 send 最多接受
63
+ # IKCP_WND_RCV(128) 个分段,超出会返回 -2 丢弃;上层按 mss 切块可避免。
64
+ def mss
65
+ KcpNative.kcp_mss(@ctx)
66
+ end
67
+
55
68
  # 取出待发送的编码包(一次一个 KCP 包),交给低层发送。没有待发送时返回 nil。
56
69
  def output
57
70
  KcpNative.kcp_output(@ctx)
58
71
  end
59
72
 
60
- # 设置 KCP 内部 MTU(默认 1400)。上层如 mnet 会额外加自己的 header + GCM tag,
61
- # 需要把 MTU 调小,保证「KCP 包 + 外层封装」仍小于路径 MTU,避免 IP 分片。
62
- def mtu=(mtu)
63
- KcpNative.kcp_setmtu(@ctx, mtu)
64
- end
65
-
66
73
  # 发送队列里待发送的包数(>0 表示窗口已满、有积压)。
67
74
  def waitsnd
68
75
  KcpNative.kcp_waitsnd(@ctx)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - kcp developers