KOTLIN - 如何将消息长度表示为 2 个二进制字节

问题描述 投票:0回答:2

我在构建 ECR(电子收银机)和 Android POS 之间的集成时遇到问题。我正在研究 android POS,我想计算消息大小并将其添加到“2 字节,二进制”中。

我有这段代码来计算并生成完整的消息

fun  generateMessage(message: String): String {
    
            return buildString {
                append(Constants.DIRECTION)
                append(AppData.getProtocolVariant())
                append(AppData.getProtocolVersion())
                append(message)
    
                val buffer = ByteBuffer.allocate(2)
                buffer.putShort(message.length.toShort())
                insert(0, buffer.array().decodeToString())
            }
        }

但是此代码仅适用于非常小的消息,因为在日志中我可以看到,对于较大的消息,此代码会添加 3 位数字并且通信失败。 完整消息的形式为

当我发送一条简单的消息“E/000”(十六进制转储 45 2f 30 30 30)时,代码起作用并且 ECR 接受它,并且在日志中我看到“��POS0110E/000”,当我看到更大的消息时像这样的“���POS0110R/S852484/RDLF****16/T93/M0/C00/DMastercard:00:0000***1234:200:200:0:0:0:1:80 3:2:133030119089:193439:497853:20230926115814:0”

其中消息大小为 3 位数字,但失败了。

那么我如何创建此消息并遵循协议

override fun sendMessage(message: String) { 
      val finalMessage = Utils.generateMessage(message) 
      server.sendMessage(finalMessage.encodeToByteArray()) }

`

将代码更改为

 fun sendMessage(bytes: ByteArray) { 
   coroutineScope.launch(Dispatchers.IO) { 
    val outputStream = socket?.getOutputStream() 
    outputStream?.write(bytes) 
    outputStream?.flush() 
  } 
}` 

仍然不被接受

指南中的示例

android kotlin binary byte ascii
2个回答
0
投票

您需要将字节写入

OutputStream
,而不是
String
。您应该更改
generateMessage()
方法以返回
ByteArray
而不是
String
,如下所示:

fun generateMessage(message: String): ByteArray {
    val x = buildString {
        append(Constants.DIRECTION)
        append(AppData.getProtocolVariant())
        append(AppData.getProtocolVersion())
        append(message)
    }
    // Create byte array containing 2-byte message length (binary) followed
    //  by the actual message
    val buffer = ByteBuffer.allocate(2 + x.length)
    buffer.putShort(x.length.toShort())
    buffer.put(x.getBytes())
    return buffer
}

另请注意,消息长度(根据您粘贴的指南中的示例)是整个消息的长度(包括标头:方向、协议版本等)。在您的代码中,您仅使用了实际消息的长度(不包括标头数据)。


0
投票

正如评论中所说,我们不能使用字符串来构造二进制消息。字符串用于文本,它们不能正确保存二进制数据。要处理二进制数据,我们必须使用

ByteArray
或其他类似的缓冲区。

我可能无法复制你的确切情况,但它应该是这样的:

@OptIn(ExperimentalStdlibApi::class)
fun main() {
    val msg = generateMessage("Hello world!")
    println(msg.decodeToString()) // ??POS0110Hello world!
    println(msg.toHexString()) // 0013504f533031313048656c6c6f20776f726c6421
}

fun generateMessage(message: String): ByteArray {
    val baos = ByteArrayOutputStream()
    val out = DataOutputStream(baos)

    val data = message.toByteArray(Charsets.US_ASCII)
    out.writeShort(data.size + 7)
    out.write(Constants.DIRECTION)
    out.write(AppData.getProtocolVariant())
    out.write(AppData.getProtocolVersion())
    out.write(data)

    return baos.toByteArray()
}

object Constants {
    val DIRECTION = "POS".toByteArray(Charsets.US_ASCII)
}

object AppData {
    fun getProtocolVariant() = "01".toByteArray(Charsets.US_ASCII)
    fun getProtocolVersion() = "10".toByteArray(Charsets.US_ASCII)
}

大小标头为

0013
(十六进制),因此为 19。这是正确的,因为
POS0110Hello world!
是 19 个字节。

请注意,我们在这里使用大端。这与示例图像中提供的格式匹配。

© www.soinside.com 2019 - 2024. All rights reserved.