我正在使用 Jetty 9.3.5,我想知道在发送 websocket 消息时处理不可靠连接的正确方法是什么,特别是:我注意到 websocket 连接没有正常关闭的情况,即使客户端一侧关闭,需要很长时间才能在服务器上触发 onClose()(例如,用户关闭笔记本电脑盖子并将其置于待机状态 - 可能需要 1-2 小时才能在服务器上接收到关闭事件服务器端)。
因此,由于客户端仍处于注册状态,服务器会继续发送开始建立的消息。当发送大量消息时,这会成为一个问题。
我测试了发送字节消息:
Session.getRemote().sendBytes(ByteBuffer, WriteCallback)
Session.getRemote().sendBytesByFuture(ByteBuffer);
为了模拟一侧的连接断开(即用户将笔记本电脑置于待机状态),在 Linux 上,我为 eth0 接口(interface)分配了一个 IP 地址,开始发送消息然后将其断开:
ifconfig eth0 192.168.1.1
ifconfig eth0 up
--- start sending messages (simple incremented numbers) and connect using Chrome browser and print them ---
ifconfig eth0 down
这样:消息仍然由 Jetty 发送,Chrome 客户端没有收到它们,服务器端没有触发 onCllose 或 onError
我关于 Jetty 的问题是:
有没有办法清除未送达的排队消息? 我试过了,但没有成功:
Session.getRemote().flush();
可以设置排队消息的最大数量吗? 我试过:
WebSocketServletFactory.getPolicy().setMaxBinaryMessageBufferSize(1)
如果客户端没有收到消息,我可以检测吗? (或者假设连接处于异常状态) 我试过:
session.getRemote().sendBytes(bb, new WriteCallback() { @Override public void writeSuccess() { //print success } @Override public void writeFailed(Throwable arg0) { //print fail } });
但是即使没有收到消息,这也会打印成功。
我也试过用,没找到解决方法:
factory.getPolicy().setIdleTimeout(...);
factory.getPolicy().setAsyncWriteTimeout(3000);
sendPing()
提前致谢!
最佳答案
不幸的是,作为消息传递协议(protocol)的 WebSocket 协议(protocol)并不是真正为消息之间的这种细微差别而设计的。
在您考虑发送下一条消息之前,第一条消息必须完成。因此,如果您有一条正在处理的消息,则无法安全地取消该消息。
充其量,可以存在一个 API 来截断带有 CONTINUATION/空负载/fin=true 的消息。
但即便如此,远程端点也不知道您取消了消息,它只会看到部分消息。
检测连接问题最好通过操作系统级事件(如 Android 的连接意图)或通过周期性的 websocket PING(将自身插入传出 websocket 帧的行前)来处理。
但是,即使使用 PING,如果您的传出 websocket 帧正在进行中,在该 websocket 帧发送完成之前甚至无法发送 PING。
RemoteEndpoint.flush()
将尝试刷新所有未决消息(和帧),而不是清除未决消息(或帧)。
至于检测客户端是否收到消息,你需要在你自己的层中实现某种消息ACK来验证,协议(protocol)没有这样的概念。 (一些建立在 websocket 之上的库/api 已经在该层中实现了消息 ACK。cometd message ack extension 作为一个真实世界的例子浮现在脑海中)
你试图解决什么样的情况?
也许使用 RemoteEndpoint.sendPartialString(String, boolean)
或 RemoteEndpoint.sendPartialBytes(ByteBuffer, boolean)
发送整个消息的较小帧可能对您有用。但是,另一端可能没有可以读取这些部分帧的 API(例如:浏览器中的 Javascript)。
关于java - Jetty Websockets - 在处理不可靠的连接时正确发送异步消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34872692/