从套接字到字节数组读取数据时出现意外的字符

时间:2017-11-24 20:35:51

标签: java c++ network-programming kafka-consumer-api

我使用 c ++ 编程从 UDP 端口获取数据。假设我们收到char buf[2000]的套接字数据。当我打印数据(转换为十六进制代码)时,消息中有一些意外数据。例如,运行代码:

for (int i =0 ; i < 2000; i++) 
{ 
  printf(" "); 
  printf("%02x", buf[i]); 
}

输出是:

EF BF BD 01 00 1C 1E 39 5A 18 40 EF BF BD 00 38 51 EF BF BD 00 00 EF BF BD EF BF BD 00 48 00 EF BF BD 00 00 00 64 EF BF BD 1F

代码中的EF BF BD模式是意外的和额外的。 要解决此问题,我将char转换为unsigned char并使用代码:

for (int i =0 ; i < 2000; i++) 
{ 
  printf(" "); 
  printf("%02x", (unsighed char)buf[i]); 
}

现在输出包含所需的结果:

aa 01 00 1c 1e 39 5a 18 50 fc 00 61 47 ae 00 00 ff b6 00 4e 01 f4 00 00 00 64 b5 4f

(请注意输出是针对不同的消息)

之后,我写信给Kafka。问题是当我从Kafka阅读消息时,这次使用Java编程使用以下代码:

ConsumerRecords<String, String> records = kafkaConsumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
byte[] temp = record.value().getBytes();
StringBuffer result = new StringBuffer();
for (byte b : temp) {
        result.append(String.format("%02X ", b));
        result.append(" "); // delimiter
                    }
System.out.println(result);

,输出为:

EF BF BD 01 00 1C 1E 39 5A 18 40 EF BF BD 00 38 51 EF BF BD 00 00 EF BF BD EF BF BD 00 48 00 EF BF BD 00 00 00 64 EF BF BD 1F

再次使用额外的EF BF BD不受欢迎的模式。

所以主要问题是如何更改 java代码以正确的方式打印消息,就像我在C ++中所做的那样。

1 个答案:

答案 0 :(得分:1)

您似乎正在读取使用单字节字符集来表示文本的字节(如ISO-8859-1或Windows-1252),但您选择使用库函数来读取它们,这些函数假设这些字节是UTF- 8文本表示。

'aa'不是字符的UTF-8表示的有效起始字节。无论您使用什么机制将字节转换为字符都知道这一点,并插入Unicode replacement character作为无效输入的指示。

的UTF-8表示是三个字节'ef bf bd'。

在字节和字符之间进行转换时,始终指定正确的字符集。这不是您在问题中显示的代码中的问题;相反,代码读取字节并将其转换为record.value()的字符串值是一个问题。正是该代码将'aa'字节解释为格式错误的UTF-8序列,并将放在字符串中以指示问题。

该代码,如果是Java,可能使用new String(bytes)。它应该使用new String(bytes, StandardCharsets.ISO_8859_1)(或可能new String(bytes, "windows-1252")或其他一些字节的字符集。)

将String转换回字节时,适用相同的规则。如果要将ª字符解码为单字节'aa',则需要使用单字节编码:

record.value().getBytes(StandardCharsets.ISO_8859_1)

正如我所说,目前record.value()不是以ª开头,而是以开头。 record.value()。getBytes()使用系统的默认字符集(UTF-8),因此返回数组的前三个字节是的UTF-8表示,即'ef bf bd'。