Искаженное шестнадцатеричное сообщение через сокет - PullRequest
0 голосов
/ 05 мая 2011

Я пытаюсь передать шестнадцатеричное сообщение с сервера C клиенту Java.Связь работает.Но шестнадцатеричное значение, которое я получаю на клиенте Java, кажется, добавлено с помощью "ff".Почему это происходит?

На стороне C, когда я печатаю байты, которые я хочу отправить (в шестнадцатеричном формате), они выглядят нормально.

Пожалуйста, смотрите код ниже:

*Сервер 1006 * 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);
    }

OutPut: значение буфера len = -36 [5] = 0 буфера [6] = 0xfffffffdc

ОБНОВЛЕНО

Вот мой вывод wireshark (это то, что сервер C отправляет на Java-клиент):

Обратите внимание, что в строке 5 "00 dc" соответствует datalen = 220, который должен быть сохраненкак таковой в len на клиенте Java.Так что в 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 ]

1 голос
/ 05 мая 2011
But the hex value that I get on Java client seems to be appended with "FF"

Integer.toHexString(buffer[index] & 0xFF ) исправит вашу проблему.

1 голос
/ 05 мая 2011

Байты в Java подписаны. Таким образом, каждое значение, для которого установлен самый значимый бит, является отрицательным значением. Когда он преобразуется в целое число, которое происходит при вызове Integer.toHexString, знак расширяется. Таким образом, если это было 10000000b, оно станет 11111111111111111111111110000000b или 0xFFFFFF80 вместо 0x80. Потому что это то же самое отрицательное значение в 32 битах. Doing

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

Должно это исправить.

Кстати, у Java нет неподписанных типов.

0 голосов
/ 05 мая 2011

Ваш первый шаг в этой ситуации должен состоять в том, чтобы увидеть, что отправляется «по проводам».Если вы можете, рассмотрите возможность использования 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;
}

Если вы выбрали первый способ, вам нужно вызывать mask () для любого значения буфера [], которое вы используете.Так что

len |= buffer[5];

будет

len |= mask(buffer[5]);

Если вы выберете второй способ, вы измените буфер с массива типа byte на int:

buffer = new int[...]

и может обновить ваш цикл while до чего-то вроде:

while( (bytes = socket_read(dis, buffer, 0, 40)) != -1)

Но это, как говорится ...

Лучшим вариантом, чем любой из них, является использование DataInputStream readUnsignedBytemethod .

Вы должны были бы самостоятельно вытащить 40 байтов из потока за раз, но было бы намного более понятно, что вы делаете, а не немного вертелось.Это был бы предпочтительный подход на мой взгляд.

0 голосов
/ 05 мая 2011

Звучит как распространение знака.len и другие переменные JAVA выглядят как подписанные, если не должны.

...