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

时间:2016-01-19 09:13:45

标签: java websocket jetty

我正在使用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

关于Jetty的问题是:

  1. 有没有办法清除未送达的排队邮件? 我试过了,但没有运气:

    Session.getRemote()平齐();

  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
                    }
                });
    
  4. 但即使没有收到消息,这也会成功。

    我也尝试使用,但找不到解决方案:

    factory.getPolicy().setIdleTimeout(...);
    factory.getPolicy().setAsyncWriteTimeout(3000);
    sendPing()
    

    提前致谢!

1 个答案:

答案 0 :(得分:1)

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

在您甚至可以考虑发送下一条消息之前,必须先完成第一条消息。因此,如果您正在处理消息,则无法安全地取消该消息。

充其量,可以使用API​​来截断该消息,并使用CONTINUATION / empty payload / fin = true。

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

检测连接问题最好使用操作系统级事件(如Android的连接意图),或通过定期websocket PING(将其自身插入到传输websocket框架的行前面。

但是,即使使用PING,如果你的传出websocket框架正在进行中,那么即使在完成发送websocket框架之前也不能发送PING。

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

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

您试图解决什么样的情况?

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