Class UltiPanelWebSocketClient
- All Implemented Interfaces:
Runnable,org.java_websocket.WebSocket,org.java_websocket.WebSocketListener
新的WebSocket客户端,基于Java-WebSocket库
New WebSocket client based on Java-WebSocket library
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate LongSupplier时钟。生产环境就是System::currentTimeMillis,测试可以替换成假时钟。private final com.google.gson.Gsonprivate static final long心跳间隔(秒)。private final ScheduledExecutorServiceprivate ScheduledFuture<?> private static final longprivate booleanprivate booleanprivate long最近一次发出 ping 的时间。private long最近一次收到 pong 的时间。0 表示从未收到过。private long最近一次测得的往返延迟,毫秒。private static final intprivate Consumer<com.google.gson.JsonObject> private Runnableprivate Runnableprivate Runnableprivate static final long判定「静默失效」的阈值:两个心跳周期没收到 pong。private intprivate final Stringprivate final StringFields inherited from class org.java_websocket.client.WebSocketClient
uri -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidconnect()连接到WebSocket服务器void断开WebSocket连接getHeaders(String token) long最近一次收到 pong 的时间戳;从未收到过时为 0。long最近一次测得的往返延迟,毫秒;尚未测到时为 -1。(package private) void一次心跳:先判活,再发 ping。booleanisAlive(long timeoutMs) 根据 pong 应答判断连接是否还活着。voidvoidvoidvoidonOpen(org.java_websocket.handshake.ServerHandshake handshakedata) private void收到 pong 时调用:记录时间并算出往返延迟。voidsendMessage(com.google.gson.JsonObject message) 发送消息到服务器voidsendPing()发送Ping消息(package private) voidsetClock(LongSupplier clock) 仅供测试替换时钟。voidsetMessageHandler(Consumer<com.google.gson.JsonObject> handler) 设置消息处理器voidsetOnConnectHandler(Runnable handler) 设置连接成功处理器voidsetOnDisconnectHandler(Runnable handler) 设置断开连接处理器voidsetOnErrorHandler(Consumer<String> handler) 设置错误处理器voidsetOnReconnectExhaustedHandler(Runnable handler) 设置重连耗尽处理器(当所有重连尝试都失败后调用)private void启动心跳任务voidsubscribeToServer(String serverId) 订阅服务器状态voidunsubscribeFromServer(String serverId) 取消订阅服务器状态Methods inherited from class org.java_websocket.client.WebSocketClient
addHeader, clearHeaders, close, close, close, closeBlocking, closeConnection, connectBlocking, connectBlocking, getAttachment, getConnection, getConnections, getDraft, getLocalSocketAddress, getLocalSocketAddress, getProtocol, getReadyState, getRemoteSocketAddress, getRemoteSocketAddress, getResourceDescriptor, getSocket, getSSLSession, getURI, hasBufferedData, hasSSLSupport, isClosed, isClosing, isFlushAndClose, isOpen, onCloseInitiated, onClosing, onMessage, onSetSSLParameters, onWebsocketClose, onWebsocketCloseInitiated, onWebsocketClosing, onWebsocketError, onWebsocketMessage, onWebsocketMessage, onWebsocketOpen, onWriteDemand, reconnect, reconnectBlocking, removeHeader, run, send, send, send, sendFragmentedFrame, sendFrame, sendFrame, setAttachment, setDnsResolver, setProxy, setSocket, setSocketFactoryMethods inherited from class org.java_websocket.AbstractWebSocket
getConnectionLostTimeout, isReuseAddr, isTcpNoDelay, setConnectionLostTimeout, setReuseAddr, setTcpNoDelay, startConnectionLostTimer, stopConnectionLostTimerMethods inherited from class org.java_websocket.WebSocketAdapter
onPreparePing, onWebsocketHandshakeReceivedAsClient, onWebsocketHandshakeReceivedAsServer, onWebsocketHandshakeSentAsClient, onWebsocketPing, onWebsocketPong
-
Field Details
-
serverId
-
token
-
heartbeatExecutor
-
isConnected
private boolean isConnected -
heartbeatTask
-
gson
private final com.google.gson.Gson gson -
messageHandler
-
onConnectHandler
-
onDisconnectHandler
-
onErrorHandler
-
onReconnectExhaustedHandler
-
MAX_RECONNECT_ATTEMPTS
private static final int MAX_RECONNECT_ATTEMPTS- See Also:
-
INITIAL_RECONNECT_DELAY_MS
private static final long INITIAL_RECONNECT_DELAY_MS- See Also:
-
reconnectAttempts
private int reconnectAttempts -
intentionalDisconnect
private boolean intentionalDisconnect -
HEARTBEAT_INTERVAL_SECONDS
private static final long HEARTBEAT_INTERVAL_SECONDS心跳间隔(秒)。- See Also:
-
PONG_TIMEOUT_MS
private static final long PONG_TIMEOUT_MS判定「静默失效」的阈值:两个心跳周期没收到 pong。取两个周期而不是一个,是为了容忍单次丢包或一次调度抖动 —— 误判的代价是把一条好连接 踢掉重连,而漏判只是晚一个周期发现。
- See Also:
-
lastPingTime
private volatile long lastPingTime最近一次发出 ping 的时间。 -
lastPongTime
private volatile long lastPongTime最近一次收到 pong 的时间。0 表示从未收到过。 -
latencyMs
private volatile long latencyMs最近一次测得的往返延迟,毫秒。 -
clock
时钟。生产环境就是System::currentTimeMillis,测试可以替换成假时钟。存在的唯一理由是让「超过阈值未收到 pong」这条判定可以被单元测试覆盖而不用
Thread.sleep—— 真等两个心跳周期是 120 秒,那种测试没人会留着。
-
-
Constructor Details
-
UltiPanelWebSocketClient
public UltiPanelWebSocketClient(String url, String serverId, String token) throws URISyntaxException 构造函数- Parameters:
url- WebSocket服务器URLserverId- 服务器IDtoken- 认证token- Throws:
URISyntaxException- 如果URL格式不正确
-
-
Method Details
-
getHeaders
-
connect
public void connect()连接到WebSocket服务器- Overrides:
connectin classorg.java_websocket.client.WebSocketClient
-
disconnect
public void disconnect()断开WebSocket连接 -
sendMessage
public void sendMessage(com.google.gson.JsonObject message) 发送消息到服务器- Parameters:
message- JSON消息对象
-
sendPing
public void sendPing()发送Ping消息- Specified by:
sendPingin interfaceorg.java_websocket.WebSocket- Overrides:
sendPingin classorg.java_websocket.client.WebSocketClient
-
subscribeToServer
订阅服务器状态- Parameters:
serverId- 要订阅的服务器ID
-
unsubscribeFromServer
取消订阅服务器状态- Parameters:
serverId- 要取消订阅的服务器ID
-
setMessageHandler
设置消息处理器- Parameters:
handler- 消息处理器
-
setOnConnectHandler
设置连接成功处理器- Parameters:
handler- 连接成功处理器
-
setOnDisconnectHandler
设置断开连接处理器- Parameters:
handler- 断开连接处理器
-
setOnErrorHandler
设置错误处理器- Parameters:
handler- 错误处理器
-
setOnReconnectExhaustedHandler
设置重连耗尽处理器(当所有重连尝试都失败后调用)- Parameters:
handler- 重连耗尽处理器
-
startHeartbeat
private void startHeartbeat()启动心跳任务 -
heartbeatTick
void heartbeatTick()一次心跳:先判活,再发 ping。「先判活」是本方法存在的理由。在此之前,连接健康的唯一判据是 socket 有没有断 —— 而一条 TCP 连接完全可以在不产生
onClose的情况下静默失效(中间设备 超时、对端进程挂起、NAT 表项过期)。那种状态下 ping 发得出去、onClose不触发、重连逻辑不启动,连接看着是好的,实际已经死了。判定为静默失效时**走
close()而不是自己另起一套重连**:close 会触发onClose,复用既有的重连状态机(含 #181 加的全局预算)。另起一套就会变成 第二个「决定要不要重连」的地方,那正是 #181 的成因。 -
recordPong
private void recordPong()收到 pong 时调用:记录时间并算出往返延迟。由
onMessage(String)在分发给 messageHandler 之前调用 —— pong 是链路层面的 事实,不该依赖上层处理器是否接线。 -
isAlive
public boolean isAlive(long timeoutMs) 根据 pong 应答判断连接是否还活着。从未收到过 pong 时返回 true。 这一条是刻意的:否则新建立的连接会在第一个 心跳周期就被判死。代价是这套机制发现不了「对端从来就不应答 pong」的情况 —— 但那是 安全的方向:面板若压根没实现 pong,我们不该把好连接反复踢掉。它能发现的是 「曾经在应答、后来不答了」,也就是静默失效。
- Parameters:
timeoutMs- 判定阈值,毫秒- Returns:
- 最近一次 pong 在阈值之内,或从未收到过 pong
-
getLatencyMs
public long getLatencyMs()最近一次测得的往返延迟,毫秒;尚未测到时为 -1。- Returns:
- 延迟毫秒数,或 -1
-
getLastPongTime
public long getLastPongTime()最近一次收到 pong 的时间戳;从未收到过时为 0。- Returns:
- 时间戳,毫秒
-
setClock
仅供测试替换时钟。 -
onOpen
public void onOpen(org.java_websocket.handshake.ServerHandshake handshakedata) - Specified by:
onOpenin classorg.java_websocket.client.WebSocketClient
-
onMessage
- Specified by:
onMessagein classorg.java_websocket.client.WebSocketClient
-
onClose
- Specified by:
onClosein classorg.java_websocket.client.WebSocketClient
-
onError
- Specified by:
onErrorin classorg.java_websocket.client.WebSocketClient
-