如何使用java byte[]准确发送如此复杂的十六进制、二进制协议数据?
我对这种东西很困惑,我应该发送什么作为最终命令,总是混淆 8 位到 1 字节,但我们该如何制作呢?是否只有屏幕截图所示的命令包 [hex]?或者是两个屏幕截图中显示的标头+命令数据包[十六进制]?
混乱细节:
在这样的图中,标题块显示的大部分内容是“Bit 7、Bit 6、..、Bit 0”,而不是“Bit 0、Bit 1、Bit 2、... Bit” 7”,我总是想知道为什么?
但是当我在代码中应用时,字节 st[0] = 位 7 或位 1 的以下顺序是什么?
另外根据这个图,这是否意味着我发送的每个命令都会始终固定 Header?
这是我尝试的代码,将位 1 作为 st[0],将位 2 作为 st 1 而不是位 7 作为 st[0]。应用断电/通电测试。
导入java.io.*; 导入java.net.*; 公开课测试 { public static void main(String[] args) 抛出 UnknownHostException、IOException { 字节st[]=新字节[256]; st[0]=0x01; // 得到 st[1]=0x02; // 标头2字节 st[2]=0x02; // 标头长度 st[3]=0; // 命令字节 st[4]=0; // 预订的 st[5]=0; st[6]=0; st[7]=0; st[8]=0x01; // 关闭电源 st[9]=0x30; st[10]=0x01; st[11]=0x00; System.out.println(st); // 这应该可行吗,我根据图表正确吗? Socket s = new Socket("192.168.1.2", 49137); DataInputStream 输入 = new DataInputStream(s.getInputStream()); DataOutputStream outToServer = new DataOutputStream(s.getOutputStream()); BufferedReader i = new BufferedReader(new InputStreamReader(s.getInputStream())); outToServer.write(st); 字符串获取; 获取 = i.readLine(); System.out.println("来自服务器:" + get); s.close(); }
}
PS:你真的会怎么做?每个十六进制命令都是手工制作的,这个PDF文件有将近100个命令,需要很多时间。或者你以不同的方式管理它们?
I am very confused with this kind of stuffs, What should I send as final command, get always confused 8 bits to 1 byte but how do we make it? Is it only the command packet [hex] as shown in screen shot? or Is it header + command packet[hex] shown in two screen shots?
Confusion details:
In such diagram header block shows mostly like "Bit 7, Bit 6,..,Bit 0" instead of "Bit 0, Bit 1, Bit 2, ... Bit 7", i always wondering why?.
But when I apply in code what is following order for byte st[0] = Bit 7 or Bit 1?
Also according to this diagram, does it mean every command I send will have Header fixed always?
This is the code I was trying by taking Bit 1 as st[0], Bit 2 as st1 instead of Bit 7 as st[0]. To apply Power off/on test.
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(); }
}
P.S: How would you do this really? Every hex command make hand by hand, this PDF file has almost 100 commands, it would take lot of time. Or you manage them in a different way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
正如@Rocky 提到的,在您的代码中,您似乎混淆了位和字节。
如果您考虑二进制中的字节,这可能会有所帮助:
如果您查看二进制表示形式,则从右侧开始计算位:一个字节有 8 位,因此位 7 是最左边的位,位 0 是最右边的位 -大多数。
十六进制(base-16)表示法之所以如此方便,是因为二进制到十六进制之间的转换比二进制到十六进制之间的转换更容易。
以二进制数 00110000 为例。如果将它们分成两部分 (0011) 和 (0000),则称为高半字节(位 7-4)和低半字节(位 3-0)。然后你可以轻松地将两个半字节转换为十六进制:
将两个半字节放在一起,你可以看到十六进制和二进制之间的关系:
所以回到你的二进制格式:
在请求数据包中,你得到响应(十六进制30),所以如果将其转换为您的位:
您可以看到位 5 和 4 已设置。
为了动态设置字节中的位,您需要使用布尔逻辑 AND 和 OR。有关单个位上的 and 和 or 的结果,请参阅以下内容:
您还可以进行 NOT 运算
对于多个位,您只需对每个位(位 7 到 0)执行操作,例如:
因此,考虑到这一点,您可以使用以下操作来设置和清除字节中的各个位:
如果要确保位 6 已设置 (1),则只需将其与 01000000(十六进制 40)进行“或”操作
如果要确保位 6 已设置很清楚(0),您只需将其与 NOT(十六进制 40)进行 AND 运算,因此
要将所有这些放入 Java 代码中,您需要使用以下二元运算符:
因此,如果您想在一个字节中设置一个位:
可以缩短为
如果您想清除一个位:
如果您想测试是否设置了一个位,您可以使用以下命令:
如果您想想要测试位 4 和位 1 是否已设置,您需要执行以下操作:
为什么是 0x12?因为
hex 12
是二进制0001 0010
,它“屏蔽”了位4和1。回到你的问题:
为了发送正确的命令字符串,你只需要创建手册中指定的正确字节数组,尽管我希望现在更清楚如何以字节为单位设置位:
注意,我在这里没有使用 DataInputStream,因为 Java 编码整数的方式可能与设备编码的方式不同它是整数。例如,在 Java 中,整数为 4 个字节且为 Big Endian(另请参阅此 SO文章)。
注意,
<<
运算符是左移运算符,它将字节中的位进行移位,上面的情况用于将两个byte
组合成一个 16-位号。左移 8 相当于乘以 256。As @Rocky mentioned, it looks like in your code you are confusing bits and bytes.
It might help if you think of a byte in binary:
If you look at the binary representation, you count the bits from the right: A byte has 8 bits, so bit 7 is the left-most bit and bit 0 is the right-most bit.
The reason why hexadecimal (base-16) notation is so convenient is because it is easier to convert between binary to hex than binary to hex.
Take the binary number 00110000. If you split these up into two parts (0011) and (0000) called the high nibble (bits 7-4) and the low nibble (bits 3-0). Then you can easily convert the two nibbles into hex:
Putting the two nibbles together, you can see the relationship between hex and binary:
So back to your binary format:
In the request packet, you are getting the response (hex 30), so if you convert that into your bit:
You can see that bit 5 and 4 are set.
In order to dynamically set bits in a byte, you'll need to use boolean logic AND and OR. See the following for results of and and or on a single bit:
You've also got the NOT operation
With multiple bits, you just perform the operation on each bit (bit 7 to 0), for example:
So with that in mind, you can use the following operations to set and clear individual bits in a byte:
If you want to ensure that bit 6 is set (1), you just have to OR it with 01000000 (hex 40)
If you wanted to ensure that bit 6 is clear (0), you just have to AND it with NOT (hex 40), so
To put all this into Java code, you've got the following binary operators:
So if you wanted to set a bit in a byte:
which can be shortened to
If you want to clear a bit:
If you want to test whether a bit is set, you'd use the following:
If you want to test whether bit 4 and bit 1 was set, you'd do the following:
Why 0x12? Because
hex 12
isbinary 0001 0010
which "masks" bit 4 and 1.Back to your question:
In order to send the correct command string, you just need to create the right byte array as specified in the manual, though I hope it is clearer now how to set bits in bytes:
Note, I'm not using a DataInputStream here as the way Java encodes integers may be different from how the device encodes it's integers. E.g. in Java and integer is 4 bytes and Big Endian (see also this SO article).
N.B. the
<<
operator is the left shift operator, which shifts the bits along in a byte and the above case is used to combine twobyte
s into a 16-bit number. Left-shifting by 8 is equivalent to multiplying by 256.在这样的图中,标题块主要显示“位 7、位 6、..、位 0”
而不是“位 0、位 1、位 2、...位 7”,我总是想知道
为什么?.
在典型的数字写入中,0 是最低有效位,7 是最高有效位,字节按照最高有效位到最低有效位 7-0 写入。
但是当我在代码中应用时,字节 st[0] = 位 7 或位 1 的以下顺序是什么?
在您的代码中,这不是设置位,这是在字节数组中设置一个字节
如果您对设置位感到紧张,请尝试这样的类:
在代码中使用它,如下所示:
另外根据此图,这是否意味着我发送的每个命令都会始终固定标头
是
这是我尝试的代码,将位 1 作为 st[0],将位 2 作为 st1,而不是将位 7 作为 st[0]。应用断电/通电测试。
我没有足够的信息来实际构建数据包,但是:
In typical number writing 0 is the least significant bit 7 the most significant and the byte is written in most significant to least significant 7-0.
In your code this is not setting bits this is setting a byte in the byte array
If you are nervous about setting bits try a class like this:
use it in you code like:
Yes
I don't have enough information to actually build the packet but:
您无需关心位顺序,因为 IP 数据包包含字节,并且较低级别的组件可确保每个字节都正确传输。
我将制作一个小方法,以十六进制很好地打印命令缓冲区,而不是 System.out.println(st) 。
You don't need to care about bit order because IP packets contain bytes and the lower level components make sure every byte is transferred correctly.
Instead of System.out.println(st) I'd make a small method that prints the command buffer nicely in hexadeciaml.