我正在开发一个基于netty的多人游戏服务器。发送给客户端的大多数消息都是特定于单个客户端的,但有时我需要向所有客户端广播相同的消息。
我不确定是否有充分的理由在我自己的地图上使用ChannelGroup。所以现在我有:
public class GameSession {
/* a map of all the players part of this game session */
private ConcurrentHashMap<String, PlayerHandler> players = new ConcurrentHashMap<String, PlayerHandler>();
private final ChannelGroup playersChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);其中PlayerHandler是:
public class PlayerHandler extends SimpleChannelInboundHandler<IncomingMessage>并包含有状态成员变量。
当一个新玩家加入(通过一些逻辑之后),他将被添加到GameSession中:
public void addPlayer(PlayerHandler p) {
if (p.getGameSessionID().equals(this.gameId)) {
players.put(p.getPlayerID(), p); //add this player to our game session
playersChannels.add(p.getChannelFromCtx()); //get channel and add to ChannelGroup
}
}假设我想播放一条消息,因为玩家请求离开(或关闭连接)
public void notifyPlayerLeft(String exPlayer) {
//Broadcast message with the id of the player that left
for (Map.Entry<String, PlayerHandler> entry : players.entrySet()) {
PlayerHandler player = entry.getValue();
player.sendPlayerLeft(exPlayer);
}
}其中sendPlayerLeft()是一个简单的方法,可以执行以下操作:
ctx.writeAndFlush(outgoingMsg)如果我使用ChannelGroup,我可以这样做:
playersChannels.writeAndFlush(outgoingMsg, matcher)但我不知道为什么这是个好主意。Netty声明它是异步发生的,但是由于PlayerHandler没有自己的线程,那么像我在NotifyPlayerLeft()中所做的那样,迭代对象是否也是异步的呢?请注意,整个场景将由一个通道/用户/线程触发。
我希望我的问题足够清楚。谢谢!
发布于 2014-12-25 23:50:22
正如您所看到的这里,Netty对一个组的默认写入同样是一个简单的迭代。从这个意义上说,您的方法在性能和并发性方面不应该存在差异。主要的区别是,它收集所有期货到一个地图,这个分组可能会帮助您跟踪任何问题提出。但是如果这已经实现了,为什么要使用您的代码呢?
发布于 2016-05-16 14:44:31
用信息更新它。因此,正如前面所述,虽然ChannelGroup对于简单的迭代非常有用,但是您也可以从API文档中获得这一好处。
Netty.io 4.1 ChannelGroup API文档
关闭的通道将自动从集合中移除,因此您不需要担心添加的通道的生命周期。一个通道可以属于多个ChannelGroup。
您可以通过扩展ChannelGroup.class来创建一个新的DefaultChannelGroup.class,并添加一些方法来在通道取消注册期间添加额外的行为,以通知某些代码某个频道未注册,然后通知其他玩家,或者进行清理。
发布于 2018-11-25 01:56:50
只需小心使用Netty的ConcurrentHashMap;它实际上是错误的;它不是线程安全。您可以在一个线程上使用并发流验证此错误,而在另一个线程上进行验证。它并不总是失败,因为它与非原子内部数组突变有关(快速并发r/w应该失败于netty,而不是jdk)。
https://stackoverflow.com/questions/27651590
复制相似问题