wastnet 是一个轻量级、高性能的 Java NIO 网络通信框架,基于 Reactor 多线程模式设计,提供 TCP 和 HTTP 服务器/客户端的完整实现。零第三方依赖,仅依赖 JDK。
- Reactor 多线程架构 - 单 Acceptor 线程 + 多 Worker 线程(独立 Selector),无锁设计
- 零依赖 - 仅依赖 JDK,无第三方库
- 高性能 - 零拷贝(
FileChannel.transferTo)、位运算批量扫描字节 - 灵活的线程模型 - 支持同步/异步双执行模式,自动适配
- SSL/TLS - 支持 PEM 证书加载、首字节嗅探自动识别明文/加密连接
- TCP 客户端 - NIO 客户端,支持自动重连、自定义编解码、SSL/TLS
- SSE (Server-Sent Events) - 事件发射器,支持超时自动关闭、自定义事件类型
| 特性 | 说明 |
|---|---|
| HTTP/1.1 | 完整支持 GET/POST/PUT/DELETE/PATCH, Pipeline, Keep-Alive, SSE |
| HTTP/2 (h2/h2c) | HPACK 头部压缩、Huffman 编码、流控、多路复用、ALPN 协商 |
| 103 Early Hints | 静态资源预加载提示(RFC 8297),H1/H2 双协议支持 |
| 路由分发 | 精确匹配、前缀匹配、正则匹配、HTTP 方法过滤 |
| 反向代理 | URL 重写、Header 变量($remote_addr 等)、H2→H1 协议转换 |
| WebSocket | 帧编解码、文本/二进制/Ping-Pong/分片帧 |
| 静态资源 | 零拷贝发送、ETag/Last-Modified 缓存、GZIP 流式压缩 |
| 文件上传 | Multipart/Form-Data 解析、流式 body 读取 |
| Chunked 编码 | 请求/响应双向 Chunked Transfer Encoding |
| GZIP 压缩 | 自动 GZIP 压缩(可配置阈值、MIME 类型过滤) |
- SSL/TLS 加密传输(JKS/PEM 证书格式)
- PEM 证书直接加载(无需 keytool 转换)
- 路径穿越防护(
..检测) - HTTP 方法白名单(静态资源默认仅允许 GET)
- 请求大小限制(URI 长度、Header 大小、Body 大小)
- 连接超时检测(空闲连接自动关闭)
- ALPN 协议协商(h2, http/1.1)
- 连接过滤 — TCP accept 级黑/白名单、IP 限流(
ConnectionFilter)
注:HTTP/2 over TLS (h2) 基于 ALPN 协议协商,需要 JDK 9+。 HTTP/2 cleartext (h2c / H2_PRIOR_KNOWLEDGE) 无此限制,JDK 8 即可使用。
<dependency>
<groupId>io.github.wycst</groupId>
<artifactId>wastnet</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>import io.github.wycst.wastnet.http.HTTPServer;
HTTPServer server = HTTPServer.of(8080)
.requestHandler((request, response) -> {
response.contentType("application/json;charset=utf-8")
.body("{\"message\": \"Hello World\"}".getBytes());
})
.start();import io.github.wycst.wastnet.http.handler.HttpRoute;
import io.github.wycst.wastnet.http.handler.HttpRouterHandler;
HttpRouterHandler router = new HttpRouterHandler();
// 精确匹配
router.get("/user", new HttpRoute() {
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws Throwable {
response.body("User page".getBytes());
}
});
// 前缀匹配
router.route("/api", new HttpRoute() {
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws Throwable {
response.body(("API: " + path).getBytes());
}
});
// 正则匹配
router.route("^/v\\d+/resource$", routeHandler);
HTTPServer.of(8080).requestHandler(router).start();HTTPServer.of(8443)
.pemSSL("cert/cert.pem", "cert/server.pem")
.h2()
.requestHandler(router)
.start();router.ws("/ws", new WebSocketResource(30 /* 空闲超时秒数 */) {
public void onOpen(WebSocketConnection conn) {
System.out.println("Connected: " + conn.id());
}
public void onMessage(WebSocketConnection conn, String msg) throws IOException {
conn.sendText("Echo: " + msg);
}
public void onClose(WebSocketConnection conn, int code, String reason) {
System.out.println("Closed: " + conn.id());
}
});router.proxy("/rest", "http://backend:8080"); // 快速方式
// 或使用完整配置
router.proxy("/rest", HttpProxyConfig.target("http://backend:8080")
.upgrade(true)
.readTimeout(5000)
.rewrite(path -> path.replaceFirst("^/rest", "")));router.resource(new HttpResourceHandler("/", "/var/www")
.earlyHints(
"<$base_path/style.css>; rel=preload; as=style",
"<$base_path/app.js>; rel=preload; as=script"
));
// $base_path 由路由器自动替换为 contextPath┌──────────────────────────────────────────────────────────────────────┐
│ TCPServer │
├──────────────────────────────────────────────────────────────────────┤
│ ChannelAcceptDispatcher (1 线程) ← 负责 Accept │
│ │ │
│ │ 轮询分发(AtomicInteger 取模) │
│ ↓ │
│ ChannelReaderWorker[0..N] (多线程, 独立 Selector) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ W-0 │ │ W-1 │ │ W-2 │ ... │ W-N │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │ │
│ ↓ │
│ ChannelRunner / ChannelSSLRunner (同步/异步执行) │
│ ↓ │
│ ChannelReader → ChannelHandler (业务处理) │
└──────────────────────────────────────────────────────────────────────┘
| 特性 | 说明 |
|---|---|
| 无锁设计 | 每个 Worker 独立 Selector,连接固定分配,无跨线程竞争 |
| 零拷贝 | FileChannel.transferTo 发送文件,内核空间直接传输 |
| 批量字节扫描 | 位掩码 + 长整型读取实现 8 字节并行分隔符检测 |
| 动态执行 | 快连接同步执行(零线程切换),慢连接异步执行(不阻塞 Worker) |
| 连接级缓冲区复用 | 每个连接持有独立读写缓冲区,减少 GC |
TcpClient 是基于 NIO 的 TCP 客户端,支持自动重连(指数退避)、自定义编解码器、SSL/TLS。
import io.github.wycst.wastnet.socket.tcp.TcpClient;
TcpClient client = TcpClient.of("127.0.0.1", 8080)
.channelHandler(new ChannelHandler<ByteBuffer>() {
public void onHandle(ChannelContext ctx, ByteBuffer message) throws IOException {
byte[] data = new byte[message.remaining()];
message.get(data);
System.out.println("Received: " + new String(data));
}
})
.connect();TcpClient client = TcpClient.of("127.0.0.1", 8080)
.autoReconnect(true) // 启用自动重连
.reconnectAttempts(10) // 最大重试次数(0 表示无限)
.reconnectDelay(1000) // 初始延迟(毫秒,指数退避)
.channelHandler(handler)
.connect();// 使用 ObjectCodec(Magic + BodyLength + SeqID + CRC16)
ObjectProtocol protocol = new ObjectProtocol() {
public Object decode(byte[] data) throws Exception {
return new String(data, "UTF-8");
}
public byte[] encode(Object msg) throws Exception {
return ((String) msg).getBytes("UTF-8");
}
};
TcpClient client = TcpClient.of("127.0.0.1", 8080)
.channelCodec(new ObjectCodec<String>(65536, protocol))
.channelHandler(myHandler)
.connect();| 方法 | 匹配方式 | 示例 |
|---|---|---|
get/post/put/delete/patch |
精确匹配 + 方法过滤 | router.get("/user", handler) |
exactRoute |
精确匹配(不限方法) | router.exactRoute("/health", handler) |
route |
前缀匹配(默认) | router.route("/api", handler) 匹配 /api/xxx |
route("^pattern") |
正则匹配 | router.route("^/v\\d+/resource$", handler) |
resource |
静态资源服务 | router.resource(new HttpResourceHandler("/", "/var/www")) |
proxy |
反向代理 | router.proxy("/api", "http://backend:8080") |
ws |
WebSocket | router.ws("/ws", new WebSocketResource()) |
h2c |
H2C 升级 | router.h2c("/h2c") |
sse |
SSE 事件推送 | router.route("/events", new SseHandler() {...}) |
方法过滤也支持 HttpMethodRoute builder 模式,为同一路径的不同方法指定不同 handler:
router.exactRoute("/api", new HttpMethodRoute()
.get(getHandler) // GET 请求
.post(postHandler) // POST 请求
.put(putHandler) // PUT 请求
);
### Context Path
```java
HttpRouterHandler router = new HttpRouterHandler("/my-app");
// 请求 /my-app/api/users → subPath = /api/usersrouter.healthRoute("/health"); // 内置端点,返回运行时长、路由统计等完整代理配置能力,参考 docs/02-guide/http-router-guide.md:
HttpProxyConfig config = HttpProxyConfig.target("http://upstream:8080")
.upgrade(true) // 支持 H2→H1 协议转换
.rewrite(path -> path.replaceFirst("^/api", "")) // 路径重写
.connectionTimeout(3000) // 连接超时
.readTimeout(5000) // 读取超时
.changeOrigin(true) // 修改 Host 头
.addHeader("X-Real-IP", "$remote_addr"); // 动态 Header 变量
router.proxy("/api", config); // 注册到路由器支持的 Header 变量:$remote_addr, $remote_port, $host, $scheme, $request_uri, $query_string, $server_addr, $server_port
wastnet 提供内置的 TCP 协议编解码器,用于自定义二进制协议的消息拆分和组装。
适用于自定义二进制协议,支持 1-4 字节长度字段、可变 header、trailer 校验、大小端字节序:
// 4 字节 header,长度字段在 offset=2 占用 2 字节,body 最大 64KB
LengthFrameCodec<byte[]> codec = new LengthFrameCodec<byte[]>(4, 2, 2, 65536);
// 使用小端字节序
codec.byteOrder(ByteOrder.LITTLE_ENDIAN);
// 包含 trailer(如 CRC16)
LengthFrameCodec<byte[]> codec = new LengthFrameCodec<byte[]>(4, 0, 2, 65536, 2, false);
// TCP 服务器中使用
TCPServer server = TCPServer.of(port)
.channelCodec(codec)
.channelHandler(handler)
.start();内置的完整消息协议:12 字节 header(Magic 0x57534E54 + BodyLength + SeqID)+ Payload + CRC16 trailer。
ObjectProtocol protocol = new ObjectProtocol() {
public Object decode(byte[] data) throws Exception { ... }
public byte[] encode(Object msg) throws Exception { ... }
};
// TCP 服务端
TCPServer.of(port)
.channelCodec(new ObjectCodec<String>(65536, protocol))
.channelHandler(handler)
.start();
// TCP 客户端
TcpClient.of(host, port)
.channelCodec(new ObjectCodec<String>(65536, protocol))
.channelHandler(handler)
.connect();详细文档参见 docs/02-guide/length-codec-guide.md。
- HPACK 头部压缩(静态表 + 动态表)
- Huffman 编码/解码(高性能位运算实现)
- 流控(连接级 + 流级 WINDOW_UPDATE)
- 多路复用(Stream 并发处理)
- H2C 升级(非加密 H2)
- H2→H1 代理转换
- 103 Early Hints
- ALPN 协商(
.h2())
HTTPServer.of(8443)
.pemSSL("cert.pem", "key.pem")
.h2()
.requestHandler(router)
.start();JDK 版本要求:h2 (HTTP/2 over TLS) 依赖 ALPN 协商,需要 JDK 9+。 h2c (HTTP/2 Cleartext) 基于明文 HTTP Upgrade,JDK 8 即可使用(参见 h2c 升级)。 对于纯内网场景,也可通过
.applicationProtocols("h2c")启用 H2_PRIOR_KNOWLEDGE 模式,减少一次 RTT(服务端始终自动支持 HTTP/1.1 回退,无需显式声明)。
HttpResourceHandler 支持发送 103 Early Hints(RFC 8297),在返回 index.html 之前通知浏览器预加载资源:
new HttpResourceHandler("/", docBase)
.earlyHints(
"<$base_path/style.css>; rel=preload; as=style",
"<$base_path/app.js>; rel=preload; as=script"
);$base_path自动替换为contextPath,无需手动拼接- H1 发送原始 103 文本,H2 发送 HEADERS 帧(
:status=103) - 仅在请求默认索引页时触发,不影响具体资源请求
// 基本用法
router.resource(new HttpResourceHandler("/", "/var/www"));
// 自定义默认文件
router.resource(new HttpResourceHandler("/", "/var/www", new File("index.htm")));
// 安全控制
new HttpResourceHandler("/", docBase)
.allowAllMethods() // 允许非 GET 方法(默认仅 GET)
.notAllowedBody("Custom 405"); // 自定义 405 响应- 自动查找
index.html/index.htm作为默认页 - 路径穿越防护(
..检测) - 默认仅允许
GET方法,其余返回 405
| 事件 | 方法 | 说明 |
|---|---|---|
| 连接建立 | onOpen(WebSocketConnection) |
新连接 |
| 文本消息 | onMessage(WebSocketConnection, String) |
UTF-8 文本 |
| 二进制消息 | onBinary(WebSocketConnection, byte[]) |
二进制数据 |
| 连接关闭 | onClose(WebSocketConnection, int, String) |
关闭事件 |
| 错误关闭 | onErrorClose(WebSocketConnection) |
异常断连 |
WebSocketConnection API:
connection.sendText("message"); // 发送文本
connection.sendBinary(data); // 发送二进制
connection.ping(); // Ping 帧
connection.close(); // 关闭连接支持配置空闲超时(秒):
new WebSocketResource(60) { ... } // 60 秒无消息自动关闭支持服务端推送事件(SSE),基于 SseEmitter 实现,线程安全,支持超时自动关闭。
router.route("/events", new SseHandler() {
@Override
public void onOpen(SseEmitter emitter) {
// 持续推送事件
for (int i = 0; i < 10; i++) {
emitter.emit("data", "count: " + i);
Thread.sleep(1000);
}
emitter.close();
}
@Override
public void onError(SseEmitter emitter, Throwable t) {
System.err.println("Client disconnected");
}
});| 方法 | 说明 |
|---|---|
emit(String data) |
发送 data-only 事件 |
emit(String event, String data) |
发送命名事件 |
emit(String event, String data, String id, Integer retry) |
完整控制 |
close() |
关闭连接 |
setTimeout(long millis) |
超时自动关闭 |
详细文档参见 docs/02-guide/sse-guide.md。
wastnet 支持 multipart/form-data 格式的文件上传解析,自动在小字段(内存)和大文件(临时文件)之间切换。
router.exactRoute("/upload", new HttpRoute() {
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws Throwable {
if (!request.isMultipart()) {
response.status(400).body("Not multipart".getBytes());
return;
}
// 遍历上传字段
for (String fieldName : request.getMultipartFieldNames()) {
MultipartField field = request.getMultipartField(fieldName);
if (field.isFile()) {
// 文件字段:transferTo 零拷贝写入
field.transferTo(new File("/tmp/" + field.getFileName()));
} else {
// 普通字段:getDataAsString 获取文本值
System.out.println(fieldName + " = " + field.getDataAsString());
}
}
response.body("OK".getBytes());
}
});超过内存阈值的文件自动落盘到临时文件,使用流式读取避免 OOM:
MultipartField field = request.getMultipartField("largeFile");
InputStream in = field.getInputStream(); // 流式读取,不加载到内存
field.transferTo(new File("/dest/file.zip")); // 或直接传输到目标文件| 属性 | 默认值 | 说明 |
|---|---|---|
wastnet.http.max-body-in-memory |
2MB | 请求 Body 内存上限,超过转为流式处理 |
wastnet.http.body-max-size |
不限 | 请求 Body 最大总大小限制(字节),适用于所有请求 |
wastnet.http.enable-temp-file |
true | 是否启用临时文件 |
wastnet.http.temp-file-dir |
系统临时目录 | 临时文件目录 |
详细使用指南参见 docs/02-guide/file-upload-guide.md。
// 从文件
server.pemSSL("cert.pem", "key.pem");
// 从 classpath
server.pemSSL("classpath:cert.pem", "classpath:key.pem");
// 从输入流
server.pemSSL(certInputStream, keyInputStream);server.ssl(true).sslContext(sslContext);所有配置项均有缺省值,默认场景下无需任何配置即可运行。仅在生产部署或特定性能调优场景下才需要关注以下配置。
完整配置参考(含所有属性、加载优先级、场景调优建议)详见:
| 属性 | 默认值 | 说明 |
|---|---|---|
wastnet.selector-timeout-ms |
1000 | Selector 超时 |
wastnet.max-runner-count |
512 | 最大并发连接数 |
wastnet.worker.select-timeout-ms |
300 | Worker Selector 超时 |
wastnet.socket.read-timeout-ms |
0 | 读取超时(0 表示不限) |
wastnet.socket.write-timeout-ms |
30000 | 写入超时(毫秒) |
wastnet.ssl.handshake-timeout-ms |
10000 | SSL 握手超时 |
wastnet.http2.initial.send-window-size |
65535 | H2 初始发送窗口 |
wastnet.http2.debug |
false | H2 Debug 日志 |
ServerConfig config = new ServerConfig();
config.setWorkerNum(8); // Worker 线程数
config.setSyncRunner(true); // 同步执行模式
config.setReadBufferSize(8192); // 读缓冲区
config.setWriteBufferSize(32768); // 写缓冲区
config.setSslHandshakeTimeoutMs(5000); // SSL 握手超时
config.setAllowPlaintextWhenSslEnabled(true); // TLS 端口允许明文服务启动时默认输出 URL 和耗时信息。可通过 startupBannerEnabled(false) 关闭:
HTTPServer.of(8080)
.startupBannerEnabled(false)
.requestHandler(...)
.start();默认输出示例:
wastnet/0.0.1-SNAPSHOT started in 1363 ms
➜ Local: http://localhost:8080
➜ Network: http://10.252.31.235:8080
也可通过继承 HTTPServer 重写 onStarted() 方法完全自定义:
class MyServer extends HTTPServer {
@Override
protected void onStarted() {
System.out.println("MyServer ready on port " + port);
}
}注意:
TCPServer的子类同样可通过重写onStarted()自定义输出。
router.notFoundHandler((request, response) -> {
response.status(404).body("Custom 404".getBytes());
});
// 全局异常处理
server.exceptionHandler((request, response, exception) -> {
response.status(500)
.contentType("application/json")
.body("{\"error\":\"Internal Error\"}".getBytes());
});
// Debug 模式(打印堆栈)
server.printStackTraceError(true);IdleStateHandler 在连接超过指定时间无读/写活动时触发回调:
import io.github.wycst.wastnet.socket.handler.IdleStateHandler;
import java.util.concurrent.TimeUnit;
server.idleStateHandler(new IdleStateHandler(10, 0, TimeUnit.SECONDS) {
@Override
public void onIdleTriggered(ChannelContext ctx, IdleStateHandler.IdleType idleType,
long triggerTotalCount, long triggerConsecutiveCount) throws Throwable {
System.out.println("Idle: conn=" + ctx.getId()
+ " type=" + idleType
+ " consecutive=" + triggerConsecutiveCount);
// Close after 3 consecutive idle triggers (30s total)
if (triggerConsecutiveCount >= 3) {
ctx.close();
}
}
});构造参数说明:
| 参数 | 说明 |
|---|---|
readerIdleTime |
读取空闲超时(≤ 0 表示不检测) |
writerIdleTime |
写入空闲超时(≤ 0 表示不检测) |
unit |
时间单位(TimeUnit.SECONDS、MILLISECONDS 等) |
回调参数说明(onIdleTriggered):
| 参数 | 说明 |
|---|---|
idleType |
空闲类型:IdleType.Read(读空闲)或 IdleType.Write(写空闲) |
triggerTotalCount |
该连接自建立以来触发的空闲总次数 |
triggerConsecutiveCount |
该连接自最后一次读写活动后连续触发的空闲次数。可用于分级处理:首次警告,多次后关闭 |
在 TCP accept 阶段拦截连接,适用于 IP 黑/白名单、连接数限流等场景,零资源浪费(被拒绝的连接不会创建 ChannelContext 和 ByteBuffer)。
// IP 黑名单
final Set<String> blacklist = new HashSet<String>(Arrays.asList("192.168.1.100", "10.0.0.5"));
HTTPServer.of(8080)
.connectionFilter(ch -> !blacklist.contains(
((InetSocketAddress) ch.getRemoteAddress()).getAddress().getHostAddress()))
.requestHandler(router)
.start();
// IP 级连接数限流
final ConcurrentHashMap<String, AtomicInteger> counters = new ConcurrentHashMap<String, AtomicInteger>();
HTTPServer.of(8080)
.connectionFilter(ch -> {
String ip = ((InetSocketAddress) ch.getRemoteAddress()).getAddress().getHostAddress();
return counters.computeIfAbsent(ip, k -> new AtomicInteger()).incrementAndGet() <= 50;
})
.requestHandler(router)
.start();connectionFilter 在 AcceptDispatcher 中执行,filter 抛异常或返回 false 时自动关闭连接并记录日志,不影响 Acceptor 主循环。
wastnet/ ← 父工程 (pom)
├── pom.xml ← 模块管理、版本管理
│
├── wastnet-core/ ← 底层网络框架 (jar)
│ ├── pom.xml ← 零外部依赖
│ └── src/main/java/io/github/wycst/wastnet/
│ ├── socket/ # TCP 核心模块
│ │ ├── tcp/ # 服务器、连接上下文
│ │ ├── handler/ # 业务处理器、空闲检测
│ │ ├── channel/ # 编解码器
│ │ └── conf/ # 配置管理
│ ├── http/ # HTTP 核心
│ │ ├── HTTPServer.java # HTTP 服务器
│ │ ├── handler/ # 路由、资源、异常处理器
│ │ ├── h2/ # HTTP/2 (HPACK/Huffman/帧/流)
│ │ ├── proxy/ # 反向代理
│ │ ├── upgrade/ # 协议升级 (WebSocket/H2C)
│ │ └── reader/ # HTTP 请求解码
│ ├── http3/ # HTTP/3 预留
│ ├── log/ # 内置日志
│ ├── util/ # 工具类
│ └── exception/ # 异常定义
│ └── src/main/resources/ # SPI 配置
│
├── wastnet-test/ ← 测试和示例 (jar)
│ ├── pom.xml # 依赖 wastnet-core
│ ├── src/main/java/ # 测试代码 + 可运行示例
│ ├── src/main/resources/ # 证书、密钥库、演示页面
│ └── test-files/ # 测试数据文件
│
├── docs/
│ ├── 02-guide/ # 使用指南
│ │ ├── http-server-api.md
│ │ ├── http-router-guide.md
│ │ ├── response-api.md
│ │ ├── file-upload-guide.md
│ │ ├── websocket-advanced-api.md
│ │ ├── h2-server-integration.md
│ │ └── length-codec-guide.md
│ ├── 03-reference/ # 配置/协议参考
│ │ ├── http-conf-reference.md
│ │ ├── socket-conf-reference.md
│ │ ├── HTTP2_PROTOCOL.md
│ │ ├── huffman-table-design.md
│ │ ├── websocket-*.md
│ ├── 05-standards/ # RFC 标准
│ │ └── rfc*.md
│ └── 04-architecture/ # 架构原理
│ └── TCPSERVER_ARCHITECTURE.md
├── SKILL.md # 编码规范
---
## 详细文档
| 文档 | 内容 |
|:-----|:-----|
| `docs/02-guide/http-router-guide.md` | 路由匹配、Context Path、反向代理配置 |
| `docs/02-guide/response-api.md` | 响应 API:状态码、Header、Chunked、GZIP、sendFile |
| `docs/02-guide/file-upload-guide.md` | 文件上传:Multipart API、大文件流式处理、配置项 |
| `docs/02-guide/sse-guide.md` | SSE 服务端推送:Emitter API、超时控制 |
| `docs/02-guide/websocket-advanced-api.md` | WebSocket 高级 API:帧编码、Ping-Pong、分片 |
| `docs/02-guide/h2-server-integration.md` | H2/H2C 服务器配置:TLS ALPN、明文升级 |
| `docs/02-guide/length-codec-guide.md` | 长度前缀帧编解码:自定义二进制协议 |
| `docs/03-reference/http-conf-reference.md` | HTTP 配置项参考(含调优建议) |
| `docs/03-reference/socket-conf-reference.md` | Socket 配置项参考 |
| `docs/03-reference/HTTP2_PROTOCOL.md` | H2 连接建立、帧结构、HPACK、流控 |
| `docs/03-reference/websocket-cheatsheet.md` | WebSocket 帧类型速查 |
| `docs/03-reference/websocket-implementation-guide.md` | WebSocket 实现细节 |
| `docs/04-architecture/TCPSERVER_ARCHITECTURE.md` | TCP 服务器架构原理 |
| `SKILL.md` | 编码规范(JDK 8 语法、代码风格) |
---
## 性能优化建议
| 场景 | 推荐 Worker 数 | 模式 | 缓冲区 |
|:-----|:-------------:|:----:|:------:|
| API 服务(小包) | CPU 核心数 | 同步 | 1-4 KB |
| 静态文件(大包) | CPU 核心数 × 2 | 异步 | 16-64 KB |
| 反向代理 | CPU 核心数 × 2 | 同步 | 4-8 KB |
| WebSocket 长连 | CPU 核心数 | 异步 | 2-4 KB |
---
## 与其他框架对比
| 特性 | wastnet | Netty | Vert.x |
|:-----|:--------:|:-----:|:------:|
| 依赖 | 无 | 多个 | 多个 |
| 学习曲线 | 低 | 中 | 中 |
| HTTP 路由 | 内置 | 需编解码器 | 内置 |
| HTTP/2 | 内置 | 需添加 handler | 内置 |
| WebSocket | 内置 | 需添加 handler | 内置 |
| 反向代理 | 内置 | 需自行实现 | 需扩展 |
| 零拷贝 | ✅ | ✅ | ✅ |
| 内存池 | 连接级复用 | 可配置 | 可配置 |
---
## 开发路线
- [x] HTTP/2 完整实现(HPACK + Huffman + 流控 + 多路复用)
- [x] 反向代理(H2→H1 转换、URL 重写、Header 变量)
- [x] 103 Early Hints(RFC 8297)
- [x] TCP 客户端(自动重连、自定义编解码、SSL/TLS)
- [x] SSE(Server-Sent Events)
- [x] 协议编解码(LengthFrameCodec、ObjectCodec)
- [ ] HTTP/3 (QUIC) 支持(预留)
- [ ] 连接池
- [ ] UDP 支持
- [ ] 监控指标(Prometheus 集成)
---
## 许可证
本项目基于 [Apache 2.0](LICENSE) 许可证开源。