如何在Kotlin Socket通信中发送含\a\b的转义序列?
在Kotlin中向Socket发送以"\a\b"结尾的消息问题
我们在大学项目中需要编写与客户端通信的服务器,服务器和机器人通过纯文本协议交互,每条命令必须以特殊符号组合\a\b结尾。
在Python中可以轻松实现:
sock.sendall("message\a\b".encode())
但在Kotlin中,\a不是有效转义序列,执行client.getOutputStream().write("message\a\b".toByteArray())会报错“\a是非法转义序列”。我尝试用\a的Unicode等效序列\u0007编写代码:
client.getOutputStream().write("Message\u0007\b".toByteArray())
可客户端仍无法识别为\a\b,无法理解消息。下面是我的完整ClientHandler类代码:
import java.io.OutputStream import java.net.Socket import java.util.Scanner class ClientHandler(private val client: Socket) { private val reader: Scanner = Scanner(client.getInputStream()) private val writer: OutputStream = client.getOutputStream() private var running: Boolean = false lateinit var username: String lateinit var hash: String lateinit var clientHash: String var key: Int = 0 var direction: Int = 0 lateinit var currenCoordinates: Coordinates lateinit var previousCoordinates: Coordinates lateinit var messageStore: String fun run() { running = true try { getUsername() sendKeyRequest() } catch (ex: Exception) { shutdown() } finally { } } private fun getUsername() { val username = reader.nextLine().toString() writer.write("Message".toByteArray(Charsets.US_ASCII)) writer.flush() client.close() println(username) } private fun write(message: String) { writer.write("Message".toByteArray(Charsets.US_ASCII)) writer.flush() println("Sent Message: $message") } private fun sendKeyRequest() { write("107 KEY REQUEST\u0007\b") } private fun shutdown() { running = false client.close() println("Connection was closed") } private fun calculateHash(username: String): Int { var sum: Int = 0 for (char in username) { sum = char.code } return (sum * 1000) % 65536 } } data class Coordinates(val x: Int, val y: Int)
解决方案
核心问题分析
你遇到的问题根本不是\u0007\b的转义问题,而是你的write方法完全没有发送传入的消息内容——它固定写死了字符串"Message",完全忽略了参数message。另外还要确保编码和Python一致(用US-ASCII),避免字节差异。
修正步骤
- 定义消息终止符常量:把
\a\b对应的Unicode转义封装成常量,方便复用和维护 - 修复
write方法:正确发送传入的消息内容,并自动追加终止符 - 修正其他逻辑错误(比如
getUsername里提前关闭客户端导致后续代码无法执行、calculateHash的求和逻辑错误)
修正后的代码片段
class ClientHandler(private val client: Socket) { private val reader: Scanner = Scanner(client.getInputStream()) private val writer: OutputStream = client.getOutputStream() private var running: Boolean = false private val MESSAGE_TERMINATOR = "\u0007\b" // 对应协议要求的\a\b // ... 其他成员变量保持不变 ... fun run() { running = true try { getUsername() sendKeyRequest() } catch (ex: Exception) { shutdown() } } private fun getUsername() { username = reader.nextLine().toString() write("Message") // 使用修正后的write方法发送消息 println(username) // 不要在这里关闭client,否则sendKeyRequest无法执行 } private fun write(message: String) { // 拼接消息内容和终止符,用US-ASCII编码生成字节数组 val fullMessage = message + MESSAGE_TERMINATOR writer.write(fullMessage.toByteArray(Charsets.US_ASCII)) writer.flush() println("Sent Message: $fullMessage") } private fun sendKeyRequest() { // 不用手动加终止符,write方法会自动处理 write("107 KEY REQUEST") } private fun calculateHash(username: String): Int { var sum = 0 // 修正求和逻辑:累加每个字符的code,而不是覆盖 for (char in username) { sum += char.code } return (sum * 1000) % 65536 } // ... 其他方法保持不变 ... }
说明
\u0007确实是ASCII响铃字符(对应\a),\b是退格字符,两者组合就是协议要求的终止符- 使用
Charsets.US_ASCII编码和Python的encode()默认行为一致,避免因编码差异导致字节不匹配 - 修复后的
write方法会自动处理终止符,避免重复编写转义序列,减少出错概率 - 移除
getUsername里的client.close(),否则后续的sendKeyRequest根本无法执行
内容的提问来源于stack exchange,提问作者user9048037
相关产品推荐
相关产品推荐

