简体   繁体   English

ConcurrentHashMap上的Netty ChannelGroup

[英]Netty ChannelGroup over ConcurrentHashMap

I'm working on a multiplayer game server based on netty. 我正在开发一款基于netty的多人游戏服务器。 Most of the messages transmitted to the clients are specific to a single client but sometimes i need to broadcast the same messages to all clients. 传输到客户端的大多数消息都是特定于单个客户端的,但有时我需要向所有客户端广播相同的消息。

I'm not sure if there's a good reason to user a ChannelGroup over my own Map. 我不确定是否有充分的理由在我自己的Map上使用ChannelGroup。 So right now i have: 所以现在我有:

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);

Where PlayerHandler is: PlayerHandler在哪里:

public class PlayerHandler extends SimpleChannelInboundHandler<IncomingMessage>

And contains stateful member variables. 并包含有状态成员变量。

When a new player joins (after going through some logic) he's being added to the GameSession: 当一个新玩家加入时(在完成一些逻辑之后),他将被添加到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
    }
}

Let's say i want to broadcast a message since a player requested to leave (or closed connection) 假设玩家要求离开(或关闭连接),我想播放一条消息

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);

    }
}

Where sendPlayerLeft() is a simple method that does something like: 其中sendPlayerLeft()是一个简单的方法,它可以执行以下操作:

ctx.writeAndFlush(outgoingMsg)

If I use a ChannelGroup I can do something like this: 如果我使用ChannelGroup,我可以这样做:

playersChannels.writeAndFlush(outgoingMsg, matcher)

but I'm not sure why that's a better idea. 但我不确定为什么这是一个更好的主意。 Netty states that it happens asynchronously but since PlayerHandler does not have its own thread, wouldn't iterating over the objects like I did in NotifyPlayerLeft() will also be async? Netty表示它是异步发生的但是由于PlayerHandler没有自己的线程,不会像我在NotifyPlayerLeft()中那样迭代对象也会异步吗? Please note that this entire scenario will be triggered by one Channel/User/Thread. 请注意,整个场景将由一个频道/用户/线程触发。

I hope that my questions are clear enough. 我希望我的问题足够清楚。 Thanks! 谢谢!

As you see here , Netty's default writing to a group is again a simple iteration. 正如您在此处所看到的,Netty对组的默认写入再次是一个简单的迭代。 In that sense, there should not be a difference in performance and concurrency with your approach. 从这个意义上讲,您的方法在性能和并发性方面应该没有区别。 The main difference is that it collects all futures into a Map, this grouping may help you track any problems raised. 主要区别在于它将所有期货收集到地图中,这种分组可以帮助您跟踪引发的任何问题。 But why use your code if this is already implemented? 但是,为什么要使用你的代码已经实现了?

Updating it with information. 用信息更新它。 So while the ChannelGroup is useful for the simple iterations as stated previously you also have this benefit taken from the API documents. 因此,虽然ChannelGroup对于前面所述的简单迭代很有用,但您也可以从API文档中获益。

Netty.io 4.1 ChannelGroup API Documents Netty.io 4.1 ChannelGroup API文档

A closed Channel is automatically removed from the collection, so that you don't need to worry about the life cycle of the added Channel. 关闭的频道会自动从集合中删除,因此您无需担心添加的频道的生命周期。 A Channel can belong to more than one ChannelGroup. 频道可以属于多个频道组。

You could go as far as creating a new ChannelGroup.class by extending the DefaultChannelGroup.class and add some methods to add additional behavior during the channel deregister to notify some code that a Channel is unregistered to then notify the other players, or do clean up. 您可以通过扩展DefaultChannelGroup.class来创建新的ChannelGroup.class ,并添加一些方法以在通道注销期间添加其他行为,以通知某些代码未注册Channel,然后通知其他玩家,或者进行清理。

Just be careful with Netty's ConcurrentHashMap; 小心Netty的ConcurrentHashMap; it is actually buggy; 它实际上是马车; it is not threadsafe. 它不是线程安全的。 You can verify this bug with concurrent stream on one thread while putting on another thread. 您可以在放置另一个线程时在一个线程上使用并发流来验证此错误。 It is not always failing since it has to do with non-atomic internal array mutations (fast pace concurrent r/w should fail with netty's but not jdk's.) 它并不总是失败,因为它与非原子内部数组突变有关(快节奏并发r / w应该与netty但不是jdk失败。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM