Java Websocket Client "leaving read() loop with no demand"



我正在为二进制WebSocket流API实现一个简单的WebSocket客户端,这是一个非常简单的API,连接后不需要身份验证或协议开销。但是,当我使用java.net.http.WebSocket实现时,我无法接收到我的WebSocket.Listener的入站消息通知。我已经使用下面的另外两个参考实现(一个cli和一个javascript(验证了API的预期工作。我使用的是OpenJDK 11.0.11+9 版本

$ java -version
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment 18.9 (build 11.0.11+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.11+9, mixed mode, sharing)

为了参考,我的实现可以在https://gist.github.com/erickj/5b6dad4a80a8d77b4e9a86e16aa4f131#file-二进制websocketclient java

据我所知,通过调试javaWebSocket实现(使用-Djdk.internal.httpclient.debug=true(,它正在退出其读取循环,并返回消息(请参阅此处的完整日志输出(:

DEBUG: [HttpClient-1-SelectorManager] [4s 175ms] SocketTube(1) no more demand for reading
DEBUG: [HttpClient-1-SelectorManager] [3s 56ms] SocketTube(1) leaving read() loop with no demand Reading: [ops=0, demand=0, stopped=false], Writing: [ops=0, demand=1]

在上面的日志消息之后,WebSocket.Listener没有收到其他消息。但是,我已经用ngrep确认,数据将继续在套接字上从服务器发送到我的客户端。

我已经追踪到上面的日志消息re:"不再需要阅读";到jdk.internal.net.http.SocketTube#read:中处理读取循环的代码

https://github.com/openjdk/jdk/blob/jdk-11%2B28/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java#L872

从对代码的简要阅读来看,我不清楚问题出在哪里,但读循环的状态管理,特别是对demand.tryDecrement()(以及我的其他工作实现,请参阅下文(的检查,让我怀疑问题实际上与openjdk WebSocket实现有关。不幸的是,我对实现或websocket协议了解不够,无法在没有更多调查的情况下进行进一步调试。

我是不是错过了一些显而易见的东西?


从上面。。。我已经确认API端点与另外两个实现(一个cli客户端和一个来自浏览器javascript(没有任何问题,如下所示:

$ websocat wss://stream.binance.com:9443/ws/adausdt@trade
const ws = new WebSocket("wss://stream.binance.com:9443/ws/adausdt@trade");
ws.onmessage = (e) => { console.log("onmessage: ", e); };

我找到了答案。。。我之前还没有完全理解WebSocket#request的用途(IMO是WebSocket API的一个非常命名和令人困惑的方面(。

我需要增加";预期请求";在创建连接后计数器至少为1。根据文件:

为了控制消息的接收,WebSocket维护一个内部计数器。此计数器的值是WebSocket尚未调用接收方法的次数。当此计数器为零时,WebSocket不会调用接收方法。当调用请求(n(时,计数器递增n。当WebSocket调用接收方法时,计数器会递减一。onOpen和onError不是接收方法。WebSocket在侦听器上的任何其他方法之前调用onOpen。WebSocket最多调用onOpen一次。WebSocket可以在任何给定的时间调用onError。如果WebSocket调用onError或onClose,那么无论计数器的值如何,都不会调用其他侦听器的方法。对于新建的WebSocket,计数器为零。

基本上,我向CompletableFuture回调添加了ws.request调用,以便继续调用WebSocket.Listener。

wsFuture.thenAccept(ws -> {
ws.request(1);
log("created websocket: %s", ws);
});

相关内容

  • 没有找到相关文章

最新更新