【问题标题】:Netty ChannelGroup over ConcurrentHashMap基于 ConcurrentHashMap 的 Netty ChannelGroup
【发布时间】:2018-11-25 09:56:50
【问题描述】:

我正在开发基于 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() 中所做的那样也会是异步的吗?请注意,整个场景将由一个 Channel/User/Thread 触发。

我希望我的问题足够清楚。 谢谢!

【问题讨论】:

    标签: java concurrency netty


    【解决方案1】:

    如您所见here,Netty 对组的默认写入再次是一个简单的迭代。从这个意义上说,您的方法在性能和并发性上应该没有差异。主要区别在于它将所有期货收集到一个地图中,这种分组可以帮助您跟踪提出的任何问题。但是,如果已经实现了,为什么还要使用您的代码呢?

    【讨论】:

    • 这主要是一种设计选择。这允许我只在 PlayerHandler 中而不是在 GameSession 中生成新消息。感谢您的回答!
    【解决方案2】:

    用信息更新它。因此,虽然 ChannelGroup 对于前面所述的简单迭代很有用,但您也可以从 API 文档中获得这种好处。

    Netty.io 4.1 ChannelGroup API Documents

    关闭的 Channel 会自动从集合中移除,因此您无需担心添加的 Channel 的生命周期。一个 Channel 可以属于多个 ChannelGroup。

    您可以通过扩展DefaultChannelGroup.class 来创建一个新的ChannelGroup.class,并添加一些方法以在频道注销期间添加其他行为,以通知某些代码频道未注册,然后通知其他玩家,或者做清理。

    【讨论】:

      【解决方案3】:

      小心使用 Netty 的 ConcurrentHashMap;它实际上是越野车;它不是线程安全的。您可以在一个线程上使用并发流来验证此错误,同时将其放在另一个线程上。它并不总是失败,因为它与非原子内部数组突变有关(快节奏并发 r/w 应该会因 netty 而不是 jdk 而失败。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-13
        相关资源
        最近更新 更多