mnet

English | 简体中文

可靠的 UDP 传输层,连接在切换网络 / 出口 IP 变化时不断开(类似 mosh)。 提供纯 Ruby ARQ 引擎,以及基于 kcp gem 的 C 引擎。

想了解内部实现原理(包结构、数据传输、切网不断连)见 DESIGN.md

特性

  • 切网不断连:会话用 128-bit token 标识(而非 TCP 的源地址四元组),源地址变化时对端自动更新指向
  • 端口跳变:mosh 式 hop,旧 socket 保留 60s 收延迟包
  • 可选加密:每包 AES-256-GCM(key,需预共享)
  • 两种引擎proto: :mnet(纯 Ruby,无 C 依赖)/ proto: :kcp(C 引擎,快)
  • 流式会话Mnet::Session 实现 IO 兼容接口(read / write / readpartial / wait_readable),可直接被 OpenSSL::SSL::SSLSocket 包装
  • 跨平台:纯 Ruby 部分天然跨平台,KCP 由 kcp gem 提供原生扩展

安装

# Gemfile
gem 'mnet'

快速开始

require 'mnet'

# ---- 服务端(回显)----
server = Mnet::Server.new('0.0.0.0', 9000)
loop do
  io = server.accept_session
  Thread.new { while (d = io.readpartial(65_536)); io.write(d); end }
end

# ---- 客户端 ----
endpoint = Mnet::Endpoint.new
sess = endpoint.dial('127.0.0.1', 9000, proto: :kcp)  # :mnet 或 :kcp
sess.write('hello')
puts sess.readpartial(1024)

引擎选择

proto 说明
:mnet 纯 Ruby ARQ,无 C 依赖,简单、易调试
:kcp C 引擎(依赖 kcp gem),快约 8 倍,需编译原生扩展

proto: :kcp 时,mnet 会自动把 KCP 引擎的 MTU 设为 IP_MTU(1280) - Mnet 头(41) - 加密开销(28,仅启用 key 时), 使「Mnet 头 + KCP 包(+ 加密)」整包不超过链路 MTU,避免 IP 分片。 如需自定义可用 kcp_mtu: 选项覆盖。

加密(预共享密钥)

每包 AES-256-GCM,两端需预共享同一个 32 字节密钥:

require 'securerandom'
key = SecureRandom.random_bytes(32)

# 服务端注册密钥(可注册多个)
server = Mnet::Server.new('0.0.0.0', 9000, keys: [key])

# 客户端带密钥拨号
sess = endpoint.dial('127.0.0.1', 9000, proto: :kcp, key: key)

会话 ID 由密钥派生(SHA256(key)[0,16]);密钥不对时服务端解密失败、直接丢弃包,客户端连不上。

TLS(嵌套)

Mnet::Session 实现了 IO 兼容接口,可被 SSLSocket 直接包装(SSLServer 写法兼容):

require 'openssl'

server = Mnet::Server.new('0.0.0.0', 9001)
ssl_server = OpenSSL::SSL::SSLServer.new(server, ssl_context)
ssl_server.start_immediately = false   # 把握手放到工作线程,不阻塞 accept
loop do
  ssl_sock = ssl_server.accept
  Thread.new do
    ssl_sock.accept
    # ...读写 ssl_sock...
  end
end

切网迁移

endpoint.hop   # 模拟切网(真实场景下客户端绑 0.0.0.0,内核自动换源地址,无需手动 hop)

基准测试

环境:loopback(127.0.0.1),pipelined echo(写端与读端并发,按总字节计)。

方案 1KB 消息吞吐
TCP(裸) ~49 MB/s
TCP + SSL ~22 MB/s
mnet 纯 Rubyproto: :mnet ~1.8 MB/s
mnet 纯 Ruby + key(AES-GCM) ~1.6 MB/s
mnet + KCPproto: :kcp ~5.0 MB/s
mnet + KCP + key(AES-GCM) ~4.1 MB/s

结论:

  • KCP 引擎比纯 Ruby 快约 2.7 倍(5.0 vs 1.8 MB/s)
  • 加密开销很小key(每包 AES-GCM)只慢 ~15~18%
  • 明文 KCP 约为 TCP 的 1/10;瓶颈在 Ruby 层的每包 glue(pack/unpack + 线程切换),不在 ARQ 算法
  • 以上是 loopback 合成基准;真实网络延迟主导时,交互式(小消息)体感无差别

复现:ruby -I lib -I ../kcp/lib test/bench_compare.rb [消息数] [消息字节]

许可

MIT。