423 字
2 分钟
防止假人压测的一种简单的手段

起因#

我之前写了一款多平台(指mc服务端)的Motd插件, 并且里面内置了一个防止假人压测的功能 这里会来简单讨论一下这个功能以及, 实现方式和部分代码, 教程基于Kotlin

原理#

判断一个客户端是否在服务器列表中ping过一次服务器

MC客户端连接到服务器时会附带客户端的IP地址, 可以用这个IP地址来判断玩家是否ping了服务器 Velocity服务端代码示例, 监听Ping服务器的event

class ProxyPingEventListener {

    @Subscribe
    fun onProxyPingEvent(event: ProxyPingEvent) {
        val ip = event.connection.remoteAddress.hostName
        // pinRecordManager是一个使用json来管理记录的管理类
        // 本质上就是一个list存储了一些ip地址
        if (pingRecordManager.exists(ip)) {
            pingRecordManager.removeRecord(ip)
        }
        pingRecordManager.addRecord(ip)
    }
}

然后监听玩家进入服务器的event

class LoginEventListener(private val proxy: ProxyServer) {

    // 定义一个超时时间, ping了一次服务器之后超过120秒没进入服务器就把这次结果
    // 作废,需要再次ping一次服务器才行
    private val  pingExpirationTime = 120
    
    @Subscribe
    fun onLogin(event: LoginEvent) {
        val ip = event.player.remoteAddress.hostName
         if (pingRecordManager.exists(ip)) {
             val record = pingRecordManager.getRecord(ip)
             val currentTimestamp = Instant.now().epochSecond
            if (currentTimestamp - record.timestamp > pingExpirationTime) {
                // PING_AGAIN_TEXT 是一个constant值用于显示玩家在ping过一次服务器之后
                // 时间超过了pingExpirationTime是超时时间, 断开连接后
                // 屏幕上显示的文字
                event.player.disconnect(Component.text(PING_AGAIN_TEXT))
                pingRecordManager.removeRecord(ip)
            }
        } else {
            // PING_FIRST_TEXT 是一个constant值用于显示玩家没有ping就进入服务器后
            // 断开连接时屏幕上显示的文字
            event.player.disconnect(Component.text(PING_FIRST_TEXT))
        }
    }
}

结尾#

这个功能是YeeeesMOTD的其中一小部分功能, 完整的代码可以在这里查看