我正在创建一个Java客户端程序,它向服务器发送命令,服务器发回确认和响应字符串。
以这种方式发送回复
client -> server : cmd_string server -> client : ack_msg(06) server -> client : response_msg
客户代码
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();
}
// ===
}
输出
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
我正在如何正确阅读最后一个值。阅读流有问题吗?
修改
其他响应被正确读取但最后一个字符应为8c但是读为0152Hex
服务器响应:06 02 b3 43 4f b3 30 b3 03 8c
按计划阅读:[0006年,0002,00b3,0043,004f,00b3,0030,00b3,0003,0152]
阅读最后一个字符的问题
编辑2
以2个数据包/流
收到响应packet 1 byte arr : 6 (ACK)
packet 2 byte arr: 2 -77 67 79 -77 48 -77 3 -116 (response)
客户端阅读的完整回复
dec: 6 2 179 67 79 179 48 179 3 338
hex: [0006, 0002, 00b3, 0043, 004f, 00b3, 0030, 00b3, 0003, 0152]
由于
答案 0 :(得分:1)
此问题中的问题是已签名变量与无符号变量的问题。当你在计算机存储器中有一个数字时,它由一堆位表示,每个位0或1.字节通常是8位,短路是16等。在无符号数字中,8位将从正0到255,但不是负数。
这是签名号码的来源。在带符号的数字中,第一位告诉您以下位是表示负值还是正值。所以现在你可以使用8位代表-128到+127。 (请注意,正范围减半,从255到127,因为您&#34;牺牲&#34;范围的一半到负数)。
那么现在如果您将签名转换为无符号会发生什么?根据你的方式,事情可能会出错。在上面的问题中,代码char c=(char)b;
正在将签名字节转换为无符号字符。正确的方法是让你的字节无符号&#34;在将其转换为char之前。你可以这样做:char c=(char)(b&0xFF);
more info on casting a byte here。
基本上,您可以记住,除了char之外,所有java编号都已签名,您需要做的就是粘贴&0xFF
以使其适用于一个字节,0xFFFF
使其成为可能等等。
有关其工作原理的详细信息如下。呼叫&amp;表示bitwise and,0xFF
是十六进制255. 255高于有符号字节的限制(127),因此数字b&0xFF
被java升级为short。但是,短符号位在第16位,而字节符号位在第8位。所以现在字节符号位变为普通数据&#39;在短路位,所以你的字节的符号基本上被丢弃。
如果你进行正常演员,java会认识到像上面那样进行直接位转换会意味着你丢失了这个标志,java希望你不要这样(至少,这是我的假设),所以它保留了给你的标志。所以,如果这不是你想要的,你明确告诉java要做什么。