kcp 0.1.2 → 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 +4 -4
- data/README.en.md +26 -3
- data/README.md +23 -2
- data/ext/kcp/kcp_native.c +48 -22
- data/lib/kcp/version.rb +1 -1
- data/lib/kcp.rb +13 -0
- 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: 571fb1bfe2f3a42c16c77b3c1e1bfe560d2cddf3f103bb74bd8c70cde474507e
|
|
4
|
+
data.tar.gz: 61968bb59630ea85f5d55c294e6cfa72e6f73c57c3ff734a02368239334c5f98
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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 (
|
|
97
|
-
there is nothing to send. **The pulled bytes must be sent verbatim to the peer**,
|
|
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
|
-
|
|
95
|
-
|
|
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/kcp_native.c
CHANGED
|
@@ -8,33 +8,46 @@
|
|
|
8
8
|
#include <stdlib.h>
|
|
9
9
|
#include <string.h>
|
|
10
10
|
|
|
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;
|
|
18
|
+
int len;
|
|
19
|
+
char data[1];
|
|
20
|
+
} kcp_pkt;
|
|
21
|
+
|
|
11
22
|
typedef struct {
|
|
12
23
|
ikcpcb *kcp;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
int outcap;
|
|
24
|
+
kcp_pkt *head;
|
|
25
|
+
kcp_pkt *tail;
|
|
16
26
|
} kcp_ctx;
|
|
17
27
|
|
|
18
|
-
/* Max bytes returned per output() call -- safely under the 64KB UDP datagram
|
|
19
|
-
limit, so a burst of KCP packets never overflows a single sendto(). */
|
|
20
|
-
#define KCP_MAX_BLOB 60000
|
|
21
|
-
|
|
22
28
|
static int shim_output(const char *buf, int len, ikcpcb *kcp, void *user) {
|
|
23
29
|
kcp_ctx *ctx = (kcp_ctx *)user;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
memcpy(
|
|
29
|
-
ctx->
|
|
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;
|
|
30
37
|
return 0;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
static void ctx_free(void *ptr) {
|
|
34
41
|
kcp_ctx *ctx = (kcp_ctx *)ptr;
|
|
35
42
|
if (ctx) {
|
|
43
|
+
kcp_pkt *pkt;
|
|
36
44
|
if (ctx->kcp) ikcp_release(ctx->kcp);
|
|
37
|
-
|
|
45
|
+
pkt = ctx->head;
|
|
46
|
+
while (pkt) {
|
|
47
|
+
kcp_pkt *next = pkt->next;
|
|
48
|
+
free(pkt);
|
|
49
|
+
pkt = next;
|
|
50
|
+
}
|
|
38
51
|
free(ctx);
|
|
39
52
|
}
|
|
40
53
|
}
|
|
@@ -108,17 +121,28 @@ static VALUE m_kcp_flush(VALUE mod, VALUE self) {
|
|
|
108
121
|
|
|
109
122
|
static VALUE m_kcp_output(VALUE mod, VALUE self) {
|
|
110
123
|
kcp_ctx *ctx = get_ctx(self);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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);
|
|
119
133
|
return buf;
|
|
120
134
|
}
|
|
121
135
|
|
|
136
|
+
static VALUE m_kcp_setmtu(VALUE mod, VALUE self, VALUE mtu) {
|
|
137
|
+
kcp_ctx *ctx = get_ctx(self);
|
|
138
|
+
return INT2NUM(ikcp_setmtu(ctx->kcp, NUM2INT(mtu)));
|
|
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
|
+
|
|
122
146
|
static VALUE m_kcp_waitsnd(VALUE mod, VALUE self) {
|
|
123
147
|
kcp_ctx *ctx = get_ctx(self);
|
|
124
148
|
return INT2NUM(ikcp_waitsnd(ctx->kcp));
|
|
@@ -133,5 +157,7 @@ void Init_kcp_native(void) {
|
|
|
133
157
|
rb_define_singleton_method(m, "kcp_update", m_kcp_update, 2);
|
|
134
158
|
rb_define_singleton_method(m, "kcp_flush", m_kcp_flush, 1);
|
|
135
159
|
rb_define_singleton_method(m, "kcp_output", m_kcp_output, 1);
|
|
160
|
+
rb_define_singleton_method(m, "kcp_setmtu", m_kcp_setmtu, 2);
|
|
161
|
+
rb_define_singleton_method(m, "kcp_mss", m_kcp_mss, 1);
|
|
136
162
|
rb_define_singleton_method(m, "kcp_waitsnd", m_kcp_waitsnd, 1);
|
|
137
163
|
}
|
data/lib/kcp/version.rb
CHANGED
data/lib/kcp.rb
CHANGED
|
@@ -52,6 +52,19 @@ 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)
|