我正在创建一个Java客户端程序,它向服务器发送命令,服务器发回确认和响应字符串 .
响应以这种方式发送回客户端 - > server:cmd_string
服务器 - >客户端:ack_msg(06)
server - > client:response_msg
Client code
public static void readStream(InputStream in){
byte[] messageByte = new byte[20];// assuming mug size -need to
// know eact msg size ?
boolean end = false;
String dataString = "";
int bytesRead = 0;
try {
DataInputStream in1 = new DataInputStream(in);
// while ctr==2 todo 2 streams
int ctr = 0;
while (ctr < 2) {//counter 2 if ACK if NAK ctr=1 todo
bytesRead = in1.read(messageByte);
if (bytesRead > -1) {
ctr++;
}
dataString += new String(messageByte, 0, bytesRead);
System.out.println("\ninput byte arr "+ctr);
for (byte b : messageByte) {
char c=(char)b;
System.out.print(" "+b);
}
}
System.out.println("MESSAGE: " + dataString + "\n bytesread " + bytesRead + " msg length "
+ dataString.length() + "\n");
char[] chars = dataString.toCharArray();
ArrayList<String> hex=new ArrayList<>();
// int[] msg ;
for (int i = 0; i < chars.length; i++) {
int val = (int) chars[i];
System.out.print(" " + val);
hex.add(String.format("%04x", val));
}
System.out.println("\n"+hex);
} catch (Exception e) {
e.printStackTrace();
}
// ===
}
Output
client Socket created ..
response:
input byte arr 1
6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
input byte arr 2
2 -77 67 79 -77 48 -77 3 -116 0 0 0 0 0 0 0 0 0 0 0
MESSAGE: ##³CO³0³##
(where # is some not supported special character )
bytesread 9 msg length 10
dec: 6 2 179 67 79 179 48 179 3 338
hex: [0006, 0002, 00b3, 0043, 004f, 00b3, 0030, 00b3, 0003, 0152]
bytes: 2 -77 67 79 -77 48 -77 3 -116 0 0 0 0 0 0 0 0 0 0 0 (bytes recieved in 2nd packet)
connection closed
问题:我正在读取最后一个值不正确,我已经使用wireshark验证服务器已将响应发送回06 02 b3 43 4f b3 30 b3 03 8c我正在如何正确读取最后一个值 . 阅读流有问题吗?
EDIT
其余的响应被正确读取但最后一个字符应为8c但读为0152Hex
来自服务器的响应:06 02 b3 43 4f b3 30 b3 03 8c
通过程序阅读:[0006,0002,000b3,0043,004f,00b3,0030,00b3,0003,0152]
阅读最后一个字符的问题
EDIT 2
Response is received as 2 packets/streams
packet 1 byte arr : 6 (ACK)
packet 2 byte arr: 2 -77 67 79 -77 48 -77 3 -116 (response)
complete response read by client
dec: 6 2 179 67 79 179 48 179 3 338
hex: [0006, 0002, 00b3, 0043, 004f, 00b3, 0030, 00b3, 0003, 0152]
谢谢
1 回答
这个问题的问题是 signed 变量与 unsigned 变量的问题 . 当你在计算机存储器中有一个数字时,它由一堆位表示,每个位为0或1.字节通常为8位,短路为16等 . 在 unsigned 数字中,8位将使您从正0到255,但不是负数 .
这是 signed 数字的来源 . 在带符号的数字中,第一位告诉您以下位是表示负值还是正值 . 所以现在你可以使用8位代表-128到127.(请注意,正范围减半,从255到127,因为你的范围的一半到负数) .
那么现在如果将 signed 转换为 unsigned 会发生什么?根据你的方式,事情可能会出错 . 在上面的问题中,代码
char c=(char)b;
正在将 signed 字节转换为 unsigned char . 执行此操作的正确方法是在将其转换为char之前"make your byte unsigned" . 你可以这样做:char c=(char)(b&0xFF);
more info on casting a byte here .基本上,你可以记住,除了char之外,所有的java数字都是有符号的,你需要做的就是粘贴
&0xFF
以使其适用于一个字节,0xFFFF
使其适用于短路等 .有关其工作原理的详细信息如下 . 调用&表示bitwise and,
0xFF
是255的十六进制.255高于有符号字节的限制(127),因此数字b&0xFF
被java升级为short . 但是,短符号位在第16位,而字节符号位在第8位 . 所以现在字节符号位在短路中变为正常'data'位,因此字节的符号基本上被丢弃 .如果你进行普通的转换,java会认识到像上面那样直接进行位转换会意味着你丢失了这个符号,并且java希望你不喜欢它(至少,这是我的假设),所以它会为你保留符号 . 所以如果这不是你想要的,你明确告诉java要做什么 .