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
相关产品推荐
相关产品推荐

