bigywater.tech
Java · 196

WebSocket:Java 如何维持全双工连接

Java 怎么维持 WebSocket 的全双工连接?握手、帧、关闭和 JDK 客户端特有的 request(n) 背压是什么样子?这篇用 Netty 4.1 做服务端、JDK 21 做客户端,逐项验证(HTTP/2 在后面的篇目,HttpClient 见前面一篇)。

101 Switching Protocols
握手响应的状态行
0 次
从不调用 request(n) 时 onText 的回调次数
4000
服务端自定义关闭状态码,客户端 onClose 收到

握手

实测 · 本机执行输出
  客户端发出的升级请求关键头:Upgrade: websocket、Connection: Upgrade、Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==、Sec-WebSocket-Version: 13
  服务端响应:
    HTTP/1.1 101 Switching Protocols
    upgrade: websocket
    connection: upgrade
    sec-websocket-accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

消息与关闭

实测 · 本机执行输出
  事件顺序:
    onOpen
    onText echo:hello
    onBinary [1, 2, 3] last=true
    onText echo:par
    onPing 3 字节
    onText m1
    onText m2
    onText m3
    onText m4
    onText m5
    onClose 1000 "client done"
  ws.isInputClosed() = true,ws.isOutputClosed() = true
  关闭之后再 sendText:IOException

背压

实测 · 本机执行输出
  从来没有调用 request(n):服务端连发 5 条消息,客户端的 onText 被调用了 0 次
    之后调用 ws.request(2):onText 累计 2 次
    再调用 ws.request(10):累计 5 次
  onOpen 里 request(1),每次 onText 后再 request(1):服务端连发 5 条消息,客户端的 onText 被调用了 5 次

服务端主动关闭

实测 · 本机执行输出
  服务端主动发 Close(4000, "server says bye"):客户端 [onClose 4000 "server says bye"];ws.isInputClosed() = true,ws.isOutputClosed() = true

分步演示

WebSocket
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12(java.net.http.WebSocket),Netty 4.1.115.Final 作服务端(回环地址)
    • 没有验证:客户端对 ping 回 pong 的行为(Netty 默认丢弃 pong,没有观察到)、TLS(wss)、心跳超时与重连、大消息的分片重组、压缩扩展(permessage-deflate)、服务端对错误路径的拒绝(我试过的错误路径,Netty 没有回应导致客户端超时,不具代表性,没有写入)
    京ICP备2026067502号-1京公网安备11010502063487号