0

我正在尝试将十六进制消息从 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 缓冲区[6]= 0xfffffffdc

更新

这是我的 wireshark 输出(这是 C 服务器推送到 Java 客户端的内容):

请注意,在第 5 行,“00 dc”对应于 datalen=220,它应该存储在 Java 客户端的 len 中。所以Java客户端显然有一些错误。就像你们都提到的那样,我可以使用 Integer.toHexString(((int)buffer[index]) & 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<.    
4

4 回答 4

1
But the hex value that I get on Java client seems to be appended with "FF"

Integer.toHexString(buffer[index] & 0xFF )将解决您的问题。

于 2011-05-05T13:30:30.333 回答
1

java中的字节是有符号的。因此,设置了最高有效位的每个值都是负值。当它转换为调用 Integer.toHexString 时发生的整数时,符号被扩展。因此,如果它是 10000000b,它将变为 1111111111111111111111110000000b 或 0xFFFFFF80 而不是 0x80。因为这在 32 位中是相同的负值。正在做

Integer.toHexString(((int)buffer[index]) & 0xFF)

应该修复它。

顺便说一句,java 没有无符号类型。

于 2011-05-05T13:34:27.080 回答
0

听起来像符号位传播。len 和其他 JAVA 变量在它们不应该被签名的时候看起来像是签名的。

于 2011-05-05T13:28:12.937 回答
0

在这些情况下,您的第一步应该是查看“通过网络”发送的内容。如果可以,请考虑使用wiresharktcpdump来查看正在传输的内容。这样,您就可以找出没有按预期工作的地方。两者都可以监视绑定到本地 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 的 readUnsignedByte 方法

您需要自己一次从流中提取 40 个字节,但您在做什么会更清楚,而不是小题大做。在我看来,这将是首选方法。

于 2011-05-05T14:08:23.697 回答