如何处理向 cometd 中的 javascript 客户端广播动态列表

How to handle broadcasting a dynamic list to javascript clients in cometd

我的网络服务器上有一个动态列表。我希望我的 Javascript 客户能够订阅一个频道,该频道将在服务器列表中添加和删除项目时进行广播。问题在于当客户端订阅频道时如何传达列表。理想情况下,客户端以服务器上的项目列表结束,然后开始处理添加和删除。

根据我对 cometd 的理解,我看不出有什么方法可以从发送订阅列表内容的服务器触发消息。如果我做不到,那么我必须求助于向服务器调用发送列表的非 cometd 服务。该解决方案使我面临可能错过添加或删除的情况。

在我看来,这是一个更普遍的问题,但不是我在其他地方看到的解决方案。

感谢任何意见。

CometD 中,您可以使用两种方法将列表广播给客户端:

  • 每次更改时发送整个列表
  • 客户端首次连接时发送整个列表,然后仅发送更改的内容

第一种方法适用于小型列表,第二种适用于大型列表。

我将讨论第二种方法,因为使用的技术也适用于第一种方法。

为了使代码片段更清晰,我们假设您要通过频道 /room1/members.

发送聊天室成员列表

在订阅时发送整个列表

在您的房间配置代码中,您向会员频道注册了一个SubscriptionListener

private void configureRoom(String roomName) {
    final String channelName = "/" + roomName + "/members";
    ServerChannel channel = bayeuxServer.createChannelIfAbsent(channelName).getReference();
    channel.addListener(new SubscriptionListener() {
        @Override
        public void subscribed(ServerSession session, ServerChannel channel, ServerMessage message) {
            // Send back the whole list to the subscriber.
            session.deliver(sender, channelName, memberList);
        }
    });

请注意,此处您要使用 ServerSession.deliver() 将整个列表仅发送给该订阅者:其他订阅者已经拥有该列表,因此无需将其广播给所有订阅者。

发送列表更改

当列表更改时,您可以仅广播更改,例如当成员离开聊天室时:

private void memberLeft(String roomName, String memberName) { 
    int index = memberList.indexOf(memberName);
    if (index < 0) {
        return;
    }
    memberList.remove(index);
    Map<String, Object> data = new HashMap<>();
    data.put("action", "remove");
    data.put("index", index);
    String channelName = "/" + roomName + "/members";
    ServerChannel channel = bayeuxServer.getChannel(channelName);
    channel.publish(sender, data);
}

请注意,此处您要使用 ServerChannel.publish() 向所有订阅者广播更改。

客户端将看到两种类型的消息到达通道 /room1/members:一种的数据是字符串列表 - 然后它会知道它是整个列表,另一种的数据是一个对象 - 和然后它会知道这是一个列表更改。

对于后者,数据将有一个 action 字段告诉您需要执行什么操作,还有一个 index 字段告诉您需要在哪个索引处操作。 这两条消息的格式完全由您决定。

应对网络中断

当客户端暂时离线时,服务器可能会发送列表更改。对于这种情况,CometD 提供 message acknowledgement extension,它提供 server-to-client 有保证的消息传递。

对于较长的离线时间,客户端将re-handshake与服务器联系,因此它将在重新订阅时获得完整列表。 请遵循 this section of the CometD documentation.

中描述的指南