Как отправить такие сложные шестнадцатеричные, двоичные данные протокола точно с использованием байта Java []? - PullRequest
4 голосов
/ 18 августа 2011

Я очень запутался в такого рода вещах. Что я должен послать в качестве заключительной команды, всегда запутываю 8 бит в 1 байт, но как нам это сделать? Это только командный пакет [hex], как показано на снимке экрана? или это заголовок + командный пакет [hex], показанный на двух снимках экрана?

Детали путаницы:

  • В такой диаграмме заголовок блока отображается в основном как «Бит 7, Бит 6, .., Бит 0» вместо «Бит 0, Бит 1, Бит 2, ... Бит 7», мне всегда интересно, почему ?.

  • Но когда я применяю код, каков порядок следования байта st [0] = бит 7 или бит 1?

  • Кроме того, согласно этой диаграмме, означает ли это, что каждая отправляемая команда всегда будет иметь фиксированный заголовок?

  • Это код, который я пробовал, принимая бит 1 в качестве st [0], бит 2 в качестве st 1 вместо бита 7 в качестве st [0]. Чтобы применить тест Power off / on.

    import java.io.*;
    import java.net.*;
    public class test 
    {
    
    public static void main(String[] args) throws UnknownHostException, IOException 
    { 
    
        byte st[]=new byte[256];
        st[0]=0x01; // get    
        st[1]=0x02; // header 2 byte
        st[2]=0x02; // header length            
        st[3]=0;    // command byte
        st[4]=0;    // reserved
        st[5]=0;            
        st[6]=0;             
        st[7]=0;
        st[8]=0x01; // power off
        st[9]=0x30; 
        st[10]=0x01;
        st[11]=0x00; 
        System.out.println(st); // Should this work, am i correct based on diagram?
    
    
        Socket s           = new Socket("192.168.1.2", 49137);
        DataInputStream input         = new DataInputStream(s.getInputStream());          
        DataOutputStream outToServer  = new DataOutputStream(s.getOutputStream());
        BufferedReader i   = new BufferedReader(new InputStreamReader(s.getInputStream()));
        outToServer.write(st);
        String get;
        get = i.readLine();
        System.out.println("FROM SERVER: " + get);
        s.close();        
    }
    

    }

enter image description here enter image description here

П.С.: Как бы вы сделали это на самом деле? Каждая шестнадцатеричная команда создается вручную, этот PDF-файл содержит почти 100 команд, это займет много времени. Или вы управляете ими по-другому?

Ответы [ 3 ]

8 голосов
/ 27 августа 2011

Как уже упоминалось @Rocky, похоже, что в вашем коде вы путаете биты и байты.

Это может помочь, если вы думаете о байте в двоичном виде:

Binary      Decimal     Hex
00000000    0           0x00
00000001    1           0x01
00110000    48          0x30

Если вы посмотрите на двоичное представление, вы посчитаете биты справа: байт имеет 8 битов, поэтомубит 7 - самый левый бит, а бит 0 - самый правый бит.

Причина, по которой шестнадцатеричная (базовая-16) запись так удобна, заключается в том, что преобразовать двоичный код в шестнадцатеричный легче, чем двоичный.в шестнадцатеричное число.

Возьмите двоичное число 00110000. Если вы разделите их на две части (0011) и (0000), называемые верхним полубайтом (биты 7-4) и нижним полубайтом (биты 3-0),Затем вы можете легко преобразовать два полубайта в гекс:

Nibble    Hex     Decimal
0000      0       0
0001      1       1
0010      2       2
0011      3       3
0100      4       4
0101      5       5
0110      6       6
0111      7       7
1000      8       8
1001      9       9
1010      A       10
1011      B       11
1100      C       12
1101      D       13
1110      E       14
1111      F       15

Соединяя два полубайта, вы можете увидеть взаимосвязь между шестнадцатеричным и двоичным:

Binary
0011 1100

Hex
   3    C

so binary 00110100 = hex 34 = dec 60

Итак, вернемся к вашему двоичному файлуформат:

В пакете запроса вы получаете ответ (шестнадцатеричный код 30), поэтому, если вы преобразуете его в свой бит:

Hex 30 = binary 0011 0000

Вы можете видеть, что биты 5 и 4set.

Чтобы динамически устанавливать биты в байте, вам нужно использовать логическую логику AND и OR.Ниже приведены результаты для и и или для одного бита:

Bit    Bit     Result Result Result
A      B       AND    OR     XOR
0      0       0      0      0
0      1       0      1      1
1      0       0      1      1
1      1       1      1      0

У вас также есть операция NOT

Bit            Result NOT
0              1
1              0

С несколькими битами вы просто выполняете операцию надкаждый бит (биты от 7 до 0), например:

    01101010    (hex 6A)
AND 11100110    (hex E6)
  = 01100010    (hex 62)

    01101010    (hex 6A)
 OR 11100110    (hex E6)
  = 11101110    (hex EE)

NOT 00111001    (hex 3B)
  = 11000110    (hex C6)

Итак, помня об этом, вы можете использовать следующие операции для установки и очистки отдельных битов в байте:

Есливы хотите убедиться, что бит 6 установлен (1), вам просто нужно ИЛИ его с 01000000 (шестнадцатеричное 40)

    xxxxxxxx    (any value)
 OR 01000000    (hex 40)
  = x1xxxxxx

Если вы хотите убедиться, что бит 6 сброшен (0), вы простонужно И это с НЕ (шестнадцатеричное 40), поэтому

NOT 01000000    (hex 40)
  = 10111111    (hex BF)

    xxxxxxxx    (any value)
AND 10111111    (hex BF)
  = x0xxxxxx

Чтобы поместить все это в код Java, у вас есть следующие бинарные операторы:

  • |двоичное ИЛИ
  • и двоичное И
  • ~ двоичное НЕ

Итак, если вы хотите установить бит в байте:

byte anyByte;
anyByte = anyByte | 0x40;

который можно сократить до

anyByte |= 0x40;

Если вы хотите сбросить бит:

anyByte &= ~0x40;

Если вы хотите проверить, установлен ли бит, вы должны использовать следующее:

if ((anyByte & 0x40) == 0x40) ...

Если вы хотите проверить, были ли установлены бит 4 и 1, вы должны сделать следующее:

if ((anyByte & 0x12) == 0x12) ...

Почему 0x12?Потому что hex 12 - это binary 0001 0010, который «маскирует» биты 4 и 1.

Вернуться к вашему вопросу:

Чтобы отправить правильную командную строку, вам просто нужно создать правильнуюМассив байтов, как указано в руководстве, хотя я надеюсь, что теперь стало понятнее, как устанавливать биты в байтах:

Socket s = new Socket("192.168.1.2", 49137);
InputStream in = s.getInputStream());          

// send the request 
// (Note, for different requests, you'll need different, byte arrays and may
// even have different lengths (can't tell without having seen the whole manual)
byte[] st = new byte[] { 0x01, 0x30, 0x01, 0x00 };
OutputStream out = s.getOutputStream();
out.write(st);
out.flush();

// read the first header byte (bits indicate the rest of the header structure)
byte header = (byte)in.read();

// bit 1 shows whether the header represented in 2 bytes
boolean header2Byte = (header & 0x2) != 0;
// bit 2 shows whether the length is represented in 2 bytes
boolean len2Byte = (header & 0x4) != 0;

if (header2Byte) {
    // need to read the extra header (discarded here)
    in.read();
}

// missed off reading the command byte/s

int len = 0;
if (len2Byte) {
    byte[] lenByte = new byte[2];
    in.read(lenByte);

    if (isLittleEndian) {
        len = (lenByte[1] << 8) + lenByte[0];
    } else {
        len = (lenByte[0] << 8) + lenByte[1];
    }
} else {
    // only one byte signifies the length
    len = is.read();
}

byte[] data = new byte[len];
in.read(data);

// it is unclear what format the data, has but if it is a string, and encoded as
// UTF-8, then you can use the following
String stringData = new String(data, "UTF-8");

System.out.println(stringData);

// note, try-catch-finally omitted for brevity

in.close();
out.close();
s.close();

Обратите внимание, я не использую DataInputStream здесь, так как способ, которым Java кодирует целые числа, может отличатьсяот того, как устройство кодирует его целые числа.Например, в Java и целое число составляет 4 байта и Big Endian (см. Также эту статью SO ).

NB Оператор << является оператором левого сдвига, который сдвигает биты вБайт и вышеприведенный случай используются для объединения двух byte в 16-битное число.Сдвиг влево на 8 эквивалентен умножению на 256.

2 голосов
/ 29 августа 2011
  • На такой диаграмме заголовок блока отображается в основном как «Бит 7, Бит 6, .., Бит 0» вместо «Бит 0, Бит 1, Бит 2, ... Бит 7», мне всегда интересно почему?.

В типичной записи числа 0 младший значащий бит 7 самый старший, а байт записывается в старшем значащем значении 7-0.

byte  11111111
place 76543210
  • Но когда я применяю код, каков порядок следования байтов st [0] = Бит 7 или Бит 1?

В вашем коде это не установка битов, это установка байта в байтовом массиве

Если вы нервничаете из-за установки битов, попробуйте такой класс:

public class SimpleByteSetter {

  /* b is is byte you are setting
     on is if the bit is set to on or 1
     place is the bit place in the range of 0-7
  */
  public static byte set(final byte b, final boolean on, final int place) {
    if (on) { return (byte) (b | ((1 << place) & 0xFF)); }
    return (byte) (b & (~((1 << place) & 0xFF)));
  }

  // 1 == on everything else off (but only use 0!)
  public static byte set(final byte b, final int on, final int place) {
    return set(b, 1==on, place);
  }

}

используйте его в своем коде, например:

byte header = 0;
// get = 0, set = 1, place = 0
header = SimpleByteSetter(header, 0, 0 ); // get
// header 2 byte = 0, header 2 byte = 1, place = 1
header = SimpleByteSetter(header, 0, 1 ); // header 1 byte
...
st[0] = header;
  • Кроме того, согласно этой диаграмме, означает ли это, что для каждой отправляемой мной команды заголовок всегда будет фиксированным

Да

  • Это код, который я пробовал, принимая Бит 1 как st [0], Бит 2 как st1 вместо Бита 7 как st [0]. Чтобы применить тест Power off / on.

У меня недостаточно информации для создания пакета, но:

// the header is 1 byte I don't see how to make it two
// the command is 2 bytes per the table
// the parameter length is 0 so 1 byte (is there suppose to be a device id?)
byte[] st = new byte[ 1 + 2 + 1 ];

byte header = 0;
// get = 0, set = 1, place = 0
header = SimpleByteSetter(header, 0, 0 ); // get
// header 2 byte = 0, header 2 byte = 1, place = 1
header = SimpleByteSetter(header, 0, 1 ); // header 1 byte
// length 1 byte = 0, length 2 byte = 1
header = SimpleByteSetter(header, 0, 2 );
// command 1 byte = 0, command 2 byte = 1; 
header = SimpleByteSetter(header, 1, 3 );

st[0] = header;
st[1] = 0x0130 & 0xFF; // poweroff command first byte
st[2] = 0x0100 & 0xFF; // poweroff second byte
st[3] = 0;
2 голосов
/ 18 августа 2011

Вам не нужно заботиться о порядке следования битов, поскольку IP-пакеты содержат байты, а компоненты более низкого уровня обеспечивают правильную передачу каждого байта.

Вместо System.out.println (st) я бысоздайте небольшой метод, который красиво печатает буфер команд в hexadeciaml.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...