You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ktor TCP通信中优化冗余also调用以提升代码可读性的方案咨询

Ktor TCP通信中优化冗余also调用以提升代码可读性的方案咨询

这种每次读取数据都要手动用also { messageLength -= ... }来更新剩余长度的写法确实挺繁琐的,代码看起来乱糟糟的,完全影响对业务逻辑的理解。我给你几个可行的优化思路,应该能大幅提升代码的可读性:


方案一:给ByteReadChannel写扩展函数,封装读取+更新逻辑

把每种读取操作和剩余长度更新的逻辑合并成单独的扩展函数,这样调用的时候就不用重复写also了。

比如针对你用到的几种读取操作,我们可以写这些扩展函数:

// 读取Boolean并更新剩余长度
fun ByteReadChannel.readBooleanAndUpdate(remaining: Int): Pair<Boolean, Int> {
    val value = this.readBoolean()
    return value to remaining - 1
}

// 读取小端Int并更新剩余长度
fun ByteReadChannel.readIntLittleEndianAndUpdate(remaining: Int): Pair<Int, Int> {
    val value = this.readIntLittleEndian()
    return value to remaining - 4
}

// 读取指定长度的ByteArray并更新剩余长度
fun ByteReadChannel.readFullyAndUpdate(remaining: Int, byteArray: ByteArray): Pair<Unit, Int> {
    this.readFully(byteArray)
    return Unit to remaining - byteArray.size
}

然后在你的业务代码里就可以这样用:

while (true) {
    var messageLength = openReadChannel.readIntLittleEndian()
    val code = openReadChannel.readIntLittleEndian()
    println("ServerClient received: Message code:" + code + " Packet Size:" + (messageLength + 4))

    when (code) {
        1 -> {
            // 读取Boolean并更新剩余长度
            val (isLoggedIn, remainingAfterBool) = openReadChannel.readBooleanAndUpdate(messageLength)
            if (isLoggedIn) {
                // 读取问候语长度并更新
                val (greetingLength, remainingAfterGreetingLen) = openReadChannel.readIntLittleEndianAndUpdate(remainingAfterBool)
                val greeting = ByteArray(greetingLength)
                // 读取问候语内容并更新
                val (_, remainingAfterGreeting) = openReadChannel.readFullyAndUpdate(remainingAfterGreetingLen, greeting)
                // 读取IP并更新
                val (ip, finalRemaining) = openReadChannel.readIntLittleEndianAndUpdate(remainingAfterGreeting)
                println("Logged In.")
                messageLength = finalRemaining
            } else {
                messageLength = remainingAfterBool
            }
            openReadChannel.discardExact(messageLength.toLong())
        }
    }
}

方案二:封装一个PacketReader类,统一管理读取和剩余长度

如果你的数据包解析逻辑比较复杂,还可以专门写一个类来封装读取操作和剩余长度的管理,让代码更整洁:

class PacketReader(private val channel: ByteReadChannel) {
    var remainingLength: Int = 0

    fun readBoolean(): Boolean {
        val value = channel.readBoolean()
        remainingLength -= 1
        return value
    }

    fun readIntLittleEndian(): Int {
        val value = channel.readIntLittleEndian()
        remainingLength -= 4
        return value
    }

    fun readFully(byteArray: ByteArray) {
        channel.readFully(byteArray)
        remainingLength -= byteArray.size
    }
}

使用这个类的代码会更简洁,业务逻辑一目了然:

while (true) {
    val messageLength = openReadChannel.readIntLittleEndian()
    val code = openReadChannel.readIntLittleEndian()
    println("ServerClient received: Message code:" + code + " Packet Size:" + (messageLength + 4))

    when (code) {
        1 -> {
            val reader = PacketReader(openReadChannel).apply {
                remainingLength = messageLength
            }
            if (reader.readBoolean()) {
                val greetingLength = reader.readIntLittleEndian()
                val greeting = ByteArray(greetingLength)
                reader.readFully(greeting)
                val ip = reader.readIntLittleEndian()
                println("Logged In.")
            }
            // 直接用reader里的剩余长度进行丢弃
            openReadChannel.discardExact(reader.remainingLength.toLong())
        }
    }
}

这两种方案的核心都是把“读取数据+更新剩余长度”的重复逻辑抽离出来,让你的业务代码只需要关注数据包的解析逻辑,不用再被繁琐的长度更新代码干扰。你可以根据自己的代码复杂度选择适合的方案~

备注:内容来源于stack exchange,提问作者Sercurio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 13:57:46