如何处理向 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.
中描述的指南
我的网络服务器上有一个动态列表。我希望我的 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.
中描述的指南