java.lang.Object
org.java_websocket.WebSocketAdapter
org.java_websocket.AbstractWebSocket
org.java_websocket.server.WebSocketServer
io.github.theword.queqiao.core.websocket.WsServer
All Implemented Interfaces:
Runnable, org.java_websocket.WebSocketListener

public class WsServer extends org.java_websocket.server.WebSocketServer
WebSocket 服务端

握手校验:onOpen(WebSocket, ClientHandshake) 依次校验 x-self-name → x-client-origin → Authorization, 任一项失败即关闭连接。

为什么 onOpen 必须自己兜住异常:Java-WebSocket 的 WebSocketImpl.open() 实现为

 readyState = OPEN;
 try { wsl.onWebsocketOpen(this, d); }
 catch (RuntimeException e) { wsl.onWebsocketError(this, e); }   // 只上报,不关闭、不重抛
 
也就是说 onOpen 抛出的异常会被库吞掉、连接保持 OPEN, 于是"未通过鉴权"的连接仍会被 onMessage(WebSocket, String) 正常处理, 构成鉴权旁路。因此 onOpen 内部任何异常都必须主动关闭连接, 绝不允许异常逃出去。(该行为已用一次性实验实证:客户端未被关闭、服务端仍持有该连接。)

关于连接数与帧大小上限(已评估,决定不设置)

  • 总连接数上限:WebSocketServer.setMaxPendingConnections(int) 限制的是 "尚未完成握手的挂起连接"而非总连接数,语义容易被误解;本项目默认绑定回环地址 且强制 token 鉴权,暴露面很小,故不新增该配置。
  • 帧大小上限:Java-WebSocket 的 Draft_6455 默认 maxFrameSize 为 Integer.MAX_VALUE(即实际无上限)。评估后仍不设置,理由: 需要有效 token 才能连上;默认仅监听回环地址; 且帧大小上限无法阻止已鉴权客户端改用大量小消息实施 DoS。 代价则是新增一条拒绝路径与一个配置项,收益无法证明。
若将来需要对外网暴露,应重新评估这两项。
Since:
0.6.11
  • Nested Class Summary

    Nested classes/interfaces inherited from class org.java_websocket.server.WebSocketServer

    org.java_websocket.server.WebSocketServer.WebSocketWorker
  • Field Summary

    Fields inherited from class org.java_websocket.server.WebSocketServer

    decoders
  • Constructor Summary

    Constructors
    Constructor
    Description
    WsServer(InetSocketAddress address, org.slf4j.Logger logger, HandleProtocolMessage handleProtocolMessage, String serverName, String accessToken, boolean enabled)
    构造函数
    WsServer(InetSocketAddress address, org.slf4j.Logger logger, HandleProtocolMessage handleProtocolMessage, String serverName, String accessToken, boolean enabled, Consumer<WsServer> serverFailureHandler)
    构造可向生命周期所有者报告服务端级启动/运行错误的 WebSocket Server。
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    onClose(org.java_websocket.WebSocket webSocket, int code, String reason, boolean remote)
    当客户端断开连接时执行
    void
    onError(org.java_websocket.WebSocket webSocket, Exception exception)
    当连接出现异常时执行
    void
    onMessage(org.java_websocket.WebSocket webSocket, String message)
    当接收到客户端的消息时执行
    void
    onOpen(org.java_websocket.WebSocket webSocket, org.java_websocket.handshake.ClientHandshake clientHandshake)
    当客户端连接时执行 连接将依次检验 x-self-name;x-client-origin;Authorization字段
    void
    当服务器启动时执行

    Methods inherited from class org.java_websocket.server.WebSocketServer

    addConnection, allocateBuffers, broadcast, broadcast, broadcast, broadcast, broadcast, broadcast, createBuffer, getAddress, getConnections, getDraft, getLocalSocketAddress, getMaxPendingConnections, getPort, getRemoteSocketAddress, getWebSocketFactory, onCloseInitiated, onClosing, onConnect, onMessage, onWebsocketClose, onWebsocketCloseInitiated, onWebsocketClosing, onWebsocketError, onWebsocketMessage, onWebsocketMessage, onWebsocketOpen, onWriteDemand, queue, releaseBuffers, removeConnection, run, setMaxPendingConnections, setWebSocketFactory, start, stop, stop, stop

    Methods inherited from class org.java_websocket.AbstractWebSocket

    getConnectionLostTimeout, isReuseAddr, isTcpNoDelay, setConnectionLostTimeout, setReuseAddr, setTcpNoDelay, startConnectionLostTimer, stopConnectionLostTimer

    Methods inherited from class org.java_websocket.WebSocketAdapter

    onPreparePing, onWebsocketHandshakeReceivedAsClient, onWebsocketHandshakeReceivedAsServer, onWebsocketHandshakeSentAsClient, onWebsocketPing, onWebsocketPong

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • WsServer

      public WsServer(InetSocketAddress address, org.slf4j.Logger logger, HandleProtocolMessage handleProtocolMessage, String serverName, String accessToken, boolean enabled)
      构造函数
      Parameters:
      address - 地址
      logger - 日志实现
      handleProtocolMessage - 协议分发入口(由 QueQiaoRuntime 创建,与 Client 共享同一实例)
      serverName - 服务器名称,为 null 时按空串处理
      accessToken - 访问令牌(可选);为 null 或空串表示不鉴权
      enabled - 是否启用协议消息处理
    • WsServer

      public WsServer(InetSocketAddress address, org.slf4j.Logger logger, HandleProtocolMessage handleProtocolMessage, String serverName, String accessToken, boolean enabled, Consumer<WsServer> serverFailureHandler)
      构造可向生命周期所有者报告服务端级启动/运行错误的 WebSocket Server。
  • Method Details

    • onOpen

      public void onOpen(org.java_websocket.WebSocket webSocket, org.java_websocket.handshake.ClientHandshake clientHandshake)
      当客户端连接时执行 连接将依次检验 x-self-name;x-client-origin;Authorization字段

      本方法不允许任何异常逃出,原因见类注释(库会吞掉异常并保留连接)。

      Specified by:
      onOpen in class org.java_websocket.server.WebSocketServer
      Parameters:
      webSocket - 客户端
      clientHandshake - 客户端握手信息
    • onClose

      public void onClose(org.java_websocket.WebSocket webSocket, int code, String reason, boolean remote)
      当客户端断开连接时执行
      Specified by:
      onClose in class org.java_websocket.server.WebSocketServer
      Parameters:
      webSocket - 客户端
      code - 关闭码
      reason - 关闭原因
      remote - 是否是远程关闭
    • onMessage

      public void onMessage(org.java_websocket.WebSocket webSocket, String message)
      当接收到客户端的消息时执行

      协议约定:只支持文本帧。二进制帧由 Java-WebSocket 的 onMessage(WebSocket, ByteBuffer) 空实现静默忽略——本项目有意不覆写它: 覆写只能额外打一条日志、不改变任何行为,反而会在客户端持续发送二进制帧时刷屏。 若排查"客户端称已发送但服务端无响应",这是一个需要确认的方向。

      Specified by:
      onMessage in class org.java_websocket.server.WebSocketServer
      Parameters:
      webSocket - 客户端
      message - 消息
    • onError

      public void onError(org.java_websocket.WebSocket webSocket, Exception exception)
      当连接出现异常时执行
      Specified by:
      onError in class org.java_websocket.server.WebSocketServer
      Parameters:
      webSocket - 客户端,服务端级致命错误时为 null
      exception - 异常
    • onStart

      public void onStart()
      当服务器启动时执行
      Specified by:
      onStart in class org.java_websocket.server.WebSocketServer