【问题标题】:TCP/IP client incorrectly reading inputstream byte arrayTCP/IP 客户端错误地读取输入流字节数组
【发布时间】:2016-01-20 11:56:19
【问题描述】:

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

谢谢

【问题讨论】:

  • 您是否尝试过直接检查 bytesRead,而不转换为 String 并返回?也许它只是一个编码问题。
  • @HenkDeBoer 我也发布了字节图。
  • 在 8 位算术中,十六进制 8C 和十进制 -116 是相同的值。因此,您读取了正确的值,只是将其转换为错误的表示形式。
  • @DavidSchwartz 你能解释一下我应该如何转换吗?我对这些概念不熟悉。
  • @RachitaNanda 目前尚不清楚您要做什么。此外,您的代码无法产生您显示的输出。所以我很难确切地说出问题是什么。但作为开始,请停止转换为有符号类型。

标签: java tcp client


【解决方案1】:

这个问题的问题在于 signed 变量与 unsigned 变量的关系。当您在计算机内存中有一个数字时,它由一堆位表示,每个位为 0 或 1。字节通常为 8 位,short 为 16 等。在 无符号 数字中,8 位会让你从正数 0 到 255,而不是负数。

这就是有符号数字的来源。在有符号数字中,第一位告诉您后面的位代表负值还是正值。所以现在你可以用 8 位来表示 -128 到 +127。 (请注意,正数范围减半,从 255 到 127,因为您将一半的范围“牺牲”为负数)。

那么现在如果将 signed 转换为 unsigned 会发生什么?根据您的操作方式,事情可能会出错。在上述问题中,代码char c=(char)b;signed 字节转换为unsigned 字符。正确的方法是在将其转换为字符之前“使您的字节无符号”。你可以这样做:char c=(char)(b&amp;0xFF);more info on casting a byte here

基本上,您只需记住,除了 char,所有 java 数字都已签名,您只需粘贴 &amp;0xFF 使其适用于一个字节,0xFFFF 使其适用于短等。

关于这个工作原理的详细信息如下。调用 & 表示 bitwise and0xFF 是十六进制的 255。255 超出了有符号字节 (127) 的限制,因此数字 b&amp;0xFF 被 java 升级为 short。但是,短符号位位于第 16 位,而字节符号位位于第 8 位。因此,现在字节符号位成为短符号中的普通“数据”位,因此您的字节符号基本上被丢弃了。

如果您进行正常转换,java 会认识到像上面那样进行直接位转换将意味着您丢失了符号,并且 java 期望您不喜欢这样(至少,这是我的假设),因此它保留了符号为你。因此,如果这不是您想要的,您明确告诉 java 要做什么。

【讨论】:

    猜你喜欢
    • 2016-04-22
    • 1970-01-01
    • 2022-06-29
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多