我正在尝试将十六进制消息从C服务器传递到Java客户端。 沟通有效。但是我在Java客户端上获得的十六进制值似乎附加了“ff”。为什么会这样?
在C方面,当我打印要发送的字节时(以十六进制表示),它们似乎没问题。
请参阅以下代码:
C服务器:
int datalen = 220;
/* create outgoing message */
idx = 0;
en_outmsg[idx++] = FEB & 0xFF;
en_outmsg[idx++] = ENT & 0xFF;
en_outmsg[idx++] = CBA & 0xFF;
en_outmsg[idx++] = GRP & 0xFF;
en_outmsg[idx++] = OUTGOING & 0xFF;
en_outmsg[idx++] = (datalen & 0xFF00) >> 8;
en_outmsg[idx++] = datalen & 0xFF;
for(i= 0; i<39; i++){
printf("en_outmsg[%d] to send = %x\n",i, en_outmsg[i]);
}
en_outmsg[i+1] = '\n';
if (send(connected, en_outmsg, 40, 0) > 0)
{
printf("sending over\n");
}
Java客户端:
while( (bytes =dis.read(buffer, 0, 40)) != -1){
for(int index=38; index >= 0; index--) {
System.out.println("index ="+index);
System.out.println("buffer ="+Integer.toHexString(buffer[index]));
}
System.out.println("bytes="+bytes);
len = 0;
len |= buffer[5];
len = len << 8;
len |= buffer[6];
System.out.println("value of len= "+len);
}
输出: len的值= -36 缓冲液[5] = 0 buffer [6] = 0xfffffffdc
已更新
这是我的wireshark输出(这是C服务器推送到Java客户端):
请注意,在第5行“00 dc”对应于datalen = 220,它应该在len客户端上存储。因此Java客户端显然存在一些错误。就像你提到的那样,我可以使用Integer.toHexString(((int)buffer [index])&amp; 0xFF)进行打印。但我需要使用正确的十六进制值存储字节数组。请帮忙
0000 00 00 03 04 00 06 00 00 00 00 00 00 00 00 08 00 ........ ........
0010 45 00 00 5c b4 75 40 00 40 06 a0 ac c0 a8 b2 14 E..\.u@. @.......
0020 c0 a8 b2 14 09 60 b7 bb fe bd 3a 2d fe 36 cc 8c .....`.. ..:-.6..
0030 80 18 02 20 e5 c8 00 00 01 01 08 0a 00 04 8e 5f ... .... ......._
0040 00 04 8e 5f 0a 01 01 16 01 00 dc 00 01 02 03 04 ..._.... ........
0050 05 06 07 08 09 0a 0b 0c 0d 0e 0f 2b 7e 15 16 28 ........ ...+~..(
0060 ae d2 a6 ab f7 15 88 09 cf 4f 3c d0 ........ .O<.
答案 0 :(得分:1)
But the hex value that I get on Java client seems to be appended with "FF"
Integer.toHexString(buffer[index] & 0xFF )
会解决您的问题。
答案 1 :(得分:1)
java中的字节是有符号的。因此,具有最高有效位集的每个值都是负值。当它转换为调用Integer.toHexString时发生的整数时,符号会被扩展。因此,如果它是10000000b,它将变为11111111111111111111111110000000b或0xFFFFFF80而不是0x80。因为32位是相同的负值。做
Integer.toHexString(((int)buffer[index]) & 0xFF)
应该修理它。
BTW,java没有无符号类型。
答案 2 :(得分:0)
听起来像符号位传播。 len和其他JAVA变量在它们不应该看起来像签名。
答案 3 :(得分:0)
在这种情况下,您的第一步应该是“通过网络”查看正在发送的内容。如果可以,请考虑使用wireshark或tcpdump查看正在传输的内容。这样,你可以找出什么不能按预期工作。两者都可以监视绑定到本地IP的套接字以及环回套接字。
但从它的外观来看,我同意有签名/未签名的冲突正在进行。
如果你有这个输出,那么确定“谁”有问题会有所帮助。
<强>更新强>
如前所述,您需要屏蔽并仅使用最低8位,这可以通过以下方式完成:
b = b & 0xFF
你可以用两种方式将它引入你的代码,一种是通过一个简单的静态函数,你可以为每个字节调用,例如。
public static int mask(int rawbyte)
{
return (rawbyte & 0xFF);
}
另一个是DataInputStream.read()的包装函数,它将字节读入缓冲区,然后将它们全部屏蔽掉。它可能看起来像:
public static int socket_read(DataInputStream dis, int arr[], int off, int len)
{
b = new byte[len];
int rv = dis.read(b, off, len);
for(int i=0; i < len; i++)
{
arr[i] = ((int)b[i]) & 0xFF;
}
return rv;
}
如果选择第一种方式,则需要在您使用的任何buffer []值上调用mask()。所以
len |= buffer[5];
将是
len |= mask(buffer[5]);
如果您选择第二种方式,那么您可以将缓冲区从byte类型的数组更改为int:
buffer = new int[...]
并且可以将你的while循环更新为:
while( (bytes = socket_read(dis, buffer, 0, 40)) != -1)
比其中任何一个更好的选择是使用DataInputStream's readUnsignedByte method。
你需要自己一次从流中拉出40个字节,但是你要做的更清楚,而不是叮叮当当。在我看来,这将是首选方法。