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



我正在使用 Jetty 9.3.5,我想知道在发送 websocket 消息时处理不可靠连接的正确方法是什么,特别是: 我注意到 websocket 连接无法正常关闭的情况,因此,即使客户端关闭,也需要很长时间才能在服务器上触发 onClose()(例如,用户合上笔记本电脑盖并将其置于待机状态 - 可能需要 1-2 小时才能关闭事件在服务器端接收)。

因此,

由于客户端仍处于注册状态,因此服务器会不断发送开始累积的消息。这在发送大量消息时成为一个问题。

我已经测试了使用以下方式发送字节消息:

Session.getRemote().sendBytes(ByteBuffer, WriteCallback)
Session.getRemote().sendBytesByFuture(ByteBuffer);

为了模拟一侧的连接(即用户将笔记本电脑置于待机状态),在 Linux 上,我为 eth0 接口分配了一个 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没有在服务器端触发

我关于码头的问题是:

  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()

提前感谢!

不幸的是,WebSocket协议作为一种消息传递协议并不是真正为消息之间的这种细微差别而设计的。

必须先完成第一条消息,然后才能考虑发送下一条消息。 因此,如果您正在处理一条消息,则无法安全地取消该消息。

充其量,可能存在一个 API 来截断该消息,其中包含 CONTINUATION/空有效负载/fin=true。

但即便如此,远程终结点也不会知道您取消了消息,它只会看到部分消息。

检测连接问题最好通过操作系统级别的事件(如 Android 的连接意图)或通过定期的 websocket PING(将自身插入传出 websocket 帧的行前面)来处理。

但是,即使使用 PING,如果您的传出 websocket 帧正在进行中,则在该 websocket 帧完成发送之前,甚至无法发送 PING。

RemoteEndpoint.flush()将尝试刷新任何挂起的消息(和帧),而不是清除挂起的消息(或帧)。

至于检测客户端是否收到消息,您需要在自己的层中实现某种消息 ACK 以验证协议没有这样的概念。 (一些构建在websocket之上的libs/api已经在该层中实现了消息ACK。 彗星消息ack扩展作为一个现实世界的例子浮现在脑海中)

您正在尝试解决哪种情况?

也许使用 RemoteEndpoint.sendPartialString(String, boolean)RemoteEndpoint.sendPartialBytes(ByteBuffer, boolean)发送整个消息的较小帧可能对您有用。 但是,另一方可能没有可以读取这些部分帧的API(例如:浏览器中的Javascript)。

相关内容

  • 没有找到相关文章

最新更新