用 wastnet 几分钟写一个 WebSocket 服务
实时双向通信是很多应用的刚需:聊天室、推送通知、在线协作、行情播报……这些都离不开 WebSocket。wastnet 原生支持 WebSocket,无需任何第三方依赖,配合路由式与编程式两种接入方式,几行代码就能跑起一个完整的双向通信服务。
下面从零开始,几分钟搞定一个可用的 WebSocket 服务。
引入依赖
<dependency>
<groupId>io.github.wycst</groupId>
<artifactId>wastnet-core</artifactId>
<version>1.0.1</version>
</dependency>
路由式:最简回声服务
最常用的是通过路由把某个 URL 直接挂成 WebSocket 端点。WebSocketResource(int) 的参数表示空闲超时(秒),WebSocketResource(boolean) 控制是否开启广播。回声场景无需广播,给个较短的空闲超时即可(如 10 秒):
import io.github.wycst.wastnet.http.HTTPServer;
import io.github.wycst.wastnet.http.handler.HttpRouterHandler;
import io.github.wycst.wastnet.http.upgrade.websocket.WebSocketConnection;
import io.github.wycst.wastnet.http.upgrade.websocket.WebSocketResource;
import java.io.IOException;
public class WsEcho {
public static void main(String[] args) throws Exception {
HttpRouterHandler router = new HttpRouterHandler();
router.ws("/ws/echo", new WebSocketResource(10) {
@Override
public void onOpen(WebSocketConnection conn) {
System.out.println("open: " + conn.id());
}
@Override
public void onMessage(WebSocketConnection conn, String message) throws IOException {
conn.sendText("echo:" + message);
}
@Override
public void onClose(WebSocketConnection conn, int code, String reason) {
System.out.println("close: " + conn.id());
}
});
HTTPServer.of(8080)
.requestHandler(router)
.start();
}
}
客户端连 ws://localhost:8080/ws/echo,发什么回什么。关键回调就三个:onOpen(连接建立)、onMessage(收到文本消息)、onClose(连接关闭)。
群组广播:聊天室
需要把一条消息推给所有人时,WebSocketResource 默认开启广播(群组)能力,通过 broadcastMessage(...) 广播;构造器参数 300 表示空闲超时(秒)。配合 WebSocketFrame.textOf(...) 构造帧:
import io.github.wycst.wastnet.http.upgrade.websocket.WebSocketFrame;
router.ws("/ws/chat", new WebSocketResource(300) {
@Override
public boolean beforeHandshake(HttpRequest request, HttpResponse response) {
return request.getParameter("name") != null;
}
@Override
public void onOpen(WebSocketConnection conn) {
String name = conn.request().getParameter("name");
conn.setAccount(name);
broadcastMessage(WebSocketFrame.textOf("system:" + name + " 加入了群聊"));
}
@Override
public void onMessage(WebSocketConnection conn, String message) throws IOException {
broadcastMessage(WebSocketFrame.textOf(conn.getAccount() + ":" + message));
}
@Override
public void onClose(WebSocketConnection conn, int code, String reason) {
broadcastMessage(WebSocketFrame.textOf("system:" + conn.getAccount() + " 离开了群聊"));
}
});
beforeHandshake(...) 在握手阶段拦截,返回 false 即拒绝连接——这里用它校验必须带 ?name=xxx。群组内任意连接都可用 broadcastMessage(...) 向所有人推送。
编程式升级:在普通 HTTP 端点里升级
有时你希望在一个普通 HTTP 请求里按需升级成 WebSocket(比如校验通过后才允许连接)。调用 HttpRequest#upgrade(...) 手动升级:
router.get("/ws/upgrade", (path, request, response) -> {
WebSocketResource ws = new WebSocketResource(false) {
@Override
public void onOpen(WebSocketConnection conn) {
conn.sendText("system: 连接已建立,echo 模式开启");
}
@Override
public void onMessage(WebSocketConnection conn, String message) throws IOException {
conn.sendText("echo:" + message);
}
@Override
public void onBinary(WebSocketConnection conn, byte[] data) throws IOException {
conn.sendBinary(data);
}
};
WebSocketConnection conn = request.upgrade(ws);
if (conn == null) {
response.setContentType("text/plain");
response.write("upgrade rejected".getBytes());
}
});
request.upgrade(ws) 返回 null 表示升级未发生(握手被拒),此时由你自行决定如何响应。升级成功后返回的WebSocketConnection对象可以自由和对端交互。
安全传输(wss)
上面的示例走明文 ws://(端口 8080)。生产环境建议启用 TLS,把 URL 升级为 wss://。wastnet 直接加载 PEM 证书即可,与 HTTP/2 用法一致:
HTTPServer.of(8443)
.pemSSL("cert/cert.pem", "cert/server.pem")
.requestHandler(router)
.start();
证书可用项目测试模块已准备好的 cert/cert.pem 与 server.pem,或自己生成。开启 TLS 后,WebSocket 端点自动通过 wss:// 提供服务。
完整示例入口
以上能力对应 wastnet 测试模块中的真实可运行示例,可直接参考:
- 聊天室 + SSE 综合演示:
wastnet-test/src/main/java/io/github/wycst/wastnet/examples/http/ChatExample.java
- 路由式 WebSocket:
wastnet-test/src/main/java/io/github/wycst/wastnet/examples/http/MiniNginxHttp2.java
- MVC 风格 WebSocket:
wastnet-test/src/main/java/io/github/wycst/wastnet/examples/http/mvc/ChatWebSocket.java
wastnet 基于 Apache 2.0 协议完全开源、免费使用。几分钟,一个双向实时的 WebSocket 服务就已经跑起来了。
相关链接