java - Jetty Websockets - 在处理不可靠的连接时正确发送异步消息

标签 java websocket jetty

我正在使用 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 的问题是:

  1. 有没有办法清除未送达的排队消息? 我试过了,但没有成功:

    Session.getRemote().flush();

  2. 可以设置排队消息的最大数量吗? 我试过:

    WebSocketServletFactory.getPolicy().setMaxBinaryMessageBufferSize(1)

  3. 如果客户端没有收到消息,我可以检测吗? (或者假设连接处于异常状态) 我试过:

    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/

相关文章:

laravel - Beyondcode laravel-websocket 未连接到服务器

java - Java 的线程是否像 Linux 上的进程一样工作?

java - 在 try/catch 之前初始化非空类型变量

java - 如何将 DefaultListModel 中的数据追加到 .txt 文件中

java - 无法恢复 Activity IndexOutOfBoundsException : Invalid index 0, 大小为 0

javascript - 如何将 WebSocketServlet 添加到具有上下文路径的嵌入式 Jetty 服务器?

tomcat - resteasy 未在 tomcat 响应错误代码 400 错误请求上运行

java - 如何捕获在测试中创建的模拟类型的实例?

java - 订阅 channel 时如何检查websocket用户是否经过身份验证?

javascript - 客户端到客户端 Websocket