2011-08-18 139 views
4

我對這種東西非常困惑,我應該如何發送最終命令,總是將8比特混淆到1字節,但我們如何做到這一點?它只是如屏幕截圖中所示的命令包[十六進制]?或者它是兩個屏幕截圖中顯示的標題+命令包[十六進制]?如何使用java byte []準確地發送如此複雜的十六進制,二進制協議數據?

混亂細節:

  • 在這樣的圖標頭塊表示大多喜歡 「位7,位6,...,位0」 而不是「位0,位1,位2,。第7位「,我總是想知道爲什麼?

  • 但是,當我在代碼中應用以下順序字節st [0] =位7或位1?

  • 也根據這個圖表,這是否意味着我發送的每個命令將始終固定標題?

  • 這是我試圖通過取位1作爲st [0],位2作爲st 1而不是位7作爲st [0]的代碼。應用關機/開機測試。

    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

P.S:你會怎麼做這是真的嗎?每個十六進制命令都是手動操作,這個PDF文件有近100個命令,這將花費很多時間。或者你以不同的方式管理它們?

+0

你的第二個點點不正確。 st [0]是一個包含8位的字節。 –

+0

我認爲你正在混淆位與字節。如果你想設置位,你將需要使用位操作。 &= | = >><<等 –

+1

我仍然感到困惑。我應該發送的最終數據包是什麼?僅僅是01 30 01 00? – YumYumYum

回答

2
  • 乘以在這樣的圖標頭塊表示大多喜歡「位7,位6,...,位0」 代替「位0,位1,位2,...位7「,我總是想知道 爲什麼?

在典型的編號寫0是最不重要的位7最重要和字節寫入最重要的最不重要的7-0。

byte 11111111 
place
  • 但是,當我在代碼中應用什麼是按以下順序爲第一字節[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; 
  • 此外,根據該圖中,它的意思是每指令i發送將具有報頭總是固定

  • 這是代碼我是嘗試將位1作爲st [0],位2作爲st1而不是位7作爲st [0]。應用關機/開機測試。

我沒有足夠的信息來建立實際的數據包,但是:

// 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; 
+0

請注意在位設置器中更改& – Clint

2

您不需要關心位順序,因爲IP數據包包含字節,而較低級別的組件確保每個字節都正確傳輸。

而不是System.out.println(st)我會做一個小的方法,很好地在十六進制中打印命令緩衝區。

+1

我還是不明白你的細節。你能詳細解釋一下嗎? – YumYumYum

+1

你的意思是說我簡單發送st [0] = 0x01; st [1] = 0x30; ST [2] = 0×01; ST [3] = 0; ?它代表那裏的命令包「01 30 01 00」? – YumYumYum

8

正如@Rocky提到的,它看起來像在你的代碼中混淆了位和字節。

如果您在二進制想到一個字節的可能有幫助:

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

如果你看看二進制表示,算上從右側的位:一個字節有8位,所以第7位是最左邊的位和位0是最右邊的位。

十六進制(base-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和位4已設置。

爲了動態設置字節中的位,您需要使用布爾邏輯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 

你還要在非操作

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),你只需要並與NOT(十六進制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 12binary 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 article)。

N.B. <<運算符是左移運算符,它將位移入一個字節中,上述情況用於將兩個byte組合成一個16位數字。左移8等效於由256