TCP / IP客户端错误地读取输入流字节数组

时间:2016-01-20 11:56:20

标签: java tcp client

我正在创建一个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]

由于

1 个答案:

答案 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 and0xFF是十六进制255. 255高于有符号字节的限制(127),因此数字b&0xFF被java升级为short。但是,短符号位在第16位,而字节符号位在第8位。所以现在字节符号位变为普通数据&#39;在短路位,所以你的字节的符号基本上被丢弃。

如果你进行正常演员,java会认识到像上面那样进行直接位转换会意味着你丢失了这个标志,java希望你不要这样(至少,这是我的假设),所以它保留了给你的标志。所以,如果这不是你想要的,你明确告诉java要做什么。