有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java ChannelId会改变吗?

我想我已经观察到了一个频道的频道ID随时间的变化。这是正常行为吗

这就是为什么我认为:

我正在编写一个游戏服务器,连接可以持续很长时间。我想引用通道,所以我将它们包装在一个玩家对象中,并使用ChannelId映射这些通道。asLongText()作为HashMap中的键。这是HashMap:

private HashMap<String, Player> players = new HashMap<String, Player>();

public void registerPlayer(Channel c, String name, String password) {
    Player p = new Player(c, name, password);
    players.put(c.id().asLongText(), p);

    try {
        Future<CredentialCheckResult> future = workerTasks.submit(new AuthenticateCredentialsTask(context.getDatabase().getConnection(), c.id().asLongText(), name, password));
        loginFutures.add(future);
    } catch (SQLException e) {
        System.out.println("["+Thread.currentThread().getName()+"] "+e.getMessage());
        return;
    }
    System.out.println("["+Thread.currentThread().getName()+"] Registered and added worker for logging in "+name+" ("+c.id().asLongText()+") \t\t total players = "+players.size());
}

public void unregisterPlayer(String id) {
    System.out.println("["+Thread.currentThread().getName()+"] Unregistering player ("+id+") \t\t total players = "+(players.size()-1));
    Player p = players.get(id);
    players.remove(id);

    if (p == null) {
        System.out.println("["+Thread.currentThread().getName()+"] P WAS NULL ("+id+") \t\t total players = "+players.size());
    }

    if (p.getChannel().isActive()) {
        p.getChannel().close();
    }
}

register和unregister方法从另一个线程运行,称为GameEngine。HashMap只会被这个线程触及

下面是我的服务器处理程序的样子,记住这一点:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    GameEngine game = context.getGameService();
    Packet p = (Packet) msg;

    if (p instanceof NewConnectionPacket) {
        NewConnectionPacket packet = (NewConnectionPacket) msg;
        game.queueLogic(new Runnable() {
            @Override
            public void run() {
                game.registerPlayer(ctx.channel(), packet.getUsername(), packet.getPassword());
            }
        });
    }
}

@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    context.getGameService().queueLogic(new Runnable() {
        @Override
        public void run() {
            context.getGameService().unregisterPlayer(ctx.channel().id().asLongText());
        }
    });
    System.out.println("["+Thread.currentThread().getName()+"] "+" Kicked for inactive channel: "+ctx.channel().id().asLongText());
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    System.err.println("["+Thread.currentThread().getName()+"] "+cause.getMessage());
    ctx.close();
}

游戏引擎。queueLogic(Runnable)是线程安全的,只对GameEngine线程的工作进行排队

当我运行服务器并登录(对所有用户使用相同的credials)几个用户,并在客户端快速断开他们的连接时,服务器似乎无法从HashMap中正确注销播放机,因为播放机。get(ChannelId.asLongText())将返回null

以下是发生这种情况的会话的日志:

    May 21, 2018 10:33:23 PM com.mchange.v2.log.MLog 
INFO: MLog clients using java 1.4+ standard logging.
May 21, 2018 10:33:23 PM com.mchange.v2.c3p0.C3P0Registry 
INFO: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
[main] GameEngine starting up...
May 21, 2018 10:33:44 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge0wf9v10qklm1j8rb36|3b94d659, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge0wf9v10qklm1j8rb36|3b94d659, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/onlinerp, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
Mon May 21 22:33:44 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Mon May 21 22:33:44 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Mon May 21 22:33:44 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
[GameEngine] Registered and added worker for logging in mads (cc2f71fffe2d38f4-0000287c-00000001-4b49379c0cc5629d-2b8fd125)          total players = 1
[pool-1-thread-1] Looking up SQL data on player mads
[pool-1-thread-1] Finished looking up SQL data on player mads, result was VERIFIED
[GameEngine] Logged in succesfully mads
[GameEngine] Registered and added worker for logging in mads (cc2f71fffe2d38f4-0000287c-00000002-777e5a8cccc572e5-65acb968)          total players = 2
[pool-1-thread-1] Looking up SQL data on player mads
[pool-1-thread-1] Finished looking up SQL data on player mads, result was VERIFIED
[GameEngine] Logged in succesfully mads
[GameEngine] Registered and added worker for logging in mads (cc2f71fffe2d38f4-0000287c-00000003-22a191d14cc5787b-f58eab6f)          total players = 3
[pool-1-thread-1] Looking up SQL data on player mads
[pool-1-thread-1] Finished looking up SQL data on player mads, result was VERIFIED
[nioEventLoopGroup-3-3] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-3]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000003-22a191d14cc5787b-f58eab6f
[GameEngine] Unregistering player (cc2f71fffe2d38f4-0000287c-00000003-22a191d14cc5787b-f58eab6f)         total players = 2
Mon May 21 22:33:51 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Mon May 21 22:33:51 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Mon May 21 22:33:51 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
[GameEngine] Registered and added worker for logging in mads (cc2f71fffe2d38f4-0000287c-00000004-edfb71804cc58079-6c340605)          total players = 3
[pool-1-thread-1] Looking up SQL data on player mads
[pool-1-thread-1] Finished looking up SQL data on player mads, result was VERIFIED
[nioEventLoopGroup-3-5] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-5]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000005-50468ea44cc5825e-52f26a37
[GameEngine] Unregistering player (cc2f71fffe2d38f4-0000287c-00000005-50468ea44cc5825e-52f26a37)         total players = 2
[GameEngine] P WAS NULL (cc2f71fffe2d38f4-0000287c-00000005-50468ea44cc5825e-52f26a37)       total players = 3
Exception in thread "GameEngine" java.lang.NullPointerException
    at com.hydrozoa.onlinerp_server.game.GameEngine.unregisterPlayer(GameEngine.java:89)
    at com.hydrozoa.onlinerp_server.net.RPServerHandler$2.run(RPServerHandler.java:49)
    at com.hydrozoa.onlinerp_server.game.GameEngine.run(GameEngine.java:128)
    at java.base/java.lang.Thread.run(Unknown Source)
[nioEventLoopGroup-3-4] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-4]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000004-edfb71804cc58079-6c340605
[nioEventLoopGroup-3-6] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-6]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000006-c3bd154facc587a0-3ef4f4b5
[nioEventLoopGroup-3-1] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-1]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000009-066e3818acc592cb-5618df97
[nioEventLoopGroup-3-8] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-8]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000008-65235126acc58ed4-10dc8b8f
[nioEventLoopGroup-3-2] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-2]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-0000000a-6034ea9b2cc59711-5b48e9f0
[nioEventLoopGroup-3-7] An existing connection was forcibly closed by the remote host
[nioEventLoopGroup-3-7]  Kicked for inactive channel: cc2f71fffe2d38f4-0000287c-00000007-693ab465acc58a8a-8251ba2a

我也尝试过使用ChannelId对象作为密钥。我觉得我对此束手无策

我用的是NioServerSocketChannel。类和NioSocketChannel。为客户端初始化

如何以不随时间变化的方式引用频道

顺便说一下,我正在使用Netty 4.1.25,这是我今天能找到的最新版本


共 (1) 个答案

  1. # 1 楼答案

    事实证明,我在所有情况下都试图从HashMap中删除Player对象,这是一个错误

    客户机可以先连接,然后空闲(导致它们无法注册,就像登录数据包注册一样),最后断开连接。事情就是这样

    我的错

    总之,ChannelId看起来使用起来很安全,而且据我所知,它不会随着时间的推移而改变