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

Java 从套接字到字节数组读取数据时出现意外字符,java,c++,network-programming,kafka-consumer-api,Java,C++,Network Programming,Kafka Consumer Api,我使用c++编程从UDP端口获取数据。假设我们将套接字数据接收到char buf[2000]。当我打印数据(转换为十六进制代码)时,消息中有一些意外数据。例如,运行代码: for (int i =0 ; i < 2000; i++) { printf(" "); printf("%02x", buf[i]); } 现在,输出包含所需的结果: aa 01 00 1c 1e 39 5a 18 50 fc 00 61 47 ae 00 ff b6 00 4e 01 f4 00

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

for (int i =0 ; i < 2000; i++) 
{ 
  printf(" "); 
  printf("%02x", buf[i]); 
}
现在,输出包含所需的结果:

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

(请注意,输出用于不同的消息)

之后,我给卡夫卡写信。问题是,当我阅读卡夫卡的消息时,这次使用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);
ConsumerRecords记录=kafkaConsumer.poll(100);
对于(消费者记录:记录){
byte[]temp=record.value().getBytes();
StringBuffer结果=新的StringBuffer();
用于(字节b:temp){
result.append(String.format(“%02X”,b));
result.append(“”;//分隔符
}
系统输出打印项次(结果);
输出为:

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

再次使用额外的
EF BF BD
不需要的模式


<> P> > <强>主问题< /St>是如何更改<强> java代码< /强>以正确的方式打印消息,就像我在C++中所做的一样。

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

“aa”不是字符的UTF-8表示形式的有效起始字节。用于将字节转换为字符的任何机制都知道这一点,并插入
,表示输入无效

是三个字节的“ef bf bd”

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

如果是Java代码,则可能使用了
新字符串(bytes)
。它应该使用
新字符串(bytes,StandardCharsets.ISO_8859_1)
(或者可能使用
新字符串(bytes,“windows-1252”)
或其他一些单字节字符集)

当您将字符串转换回字节时,同样的规则适用。如果您希望将
ª
字符解码为单字节“aa”,则需要使用单字节编码:

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

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

谢谢你的精彩回答!我尝试了
ISO_8859_1
windows-1252
,但在这两种情况下,
aa
更改为
3f 01 00 1C 1E 39 5A 18 40 3f 00 38 51 3f 00 3f 00 3f 00 48 00 3f 00 00 00 00 00 00 00 64 3f 1F
“3f”是estion标记(
),它是与
。现在,我更仔细地查看了您的数据,我想知道为什么您要尝试将其转换为字符串或从字符串转换,因为您有大量的字节,这些字节显然不是文本。您应该避免使用字符串,而只使用字节数组。在Java中,与C不同,字符和字节不是一回事。
record.value().getBytes(StandardCharsets.ISO_8859_1)