2

I'm creating a Java Client program that sends a command to server and server sends back an acknowledgement and a response string.

The response is sent back in this manner

client -> server : cmd_string

server -> client : 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

Problem: I'm reading the last value incorrect, I have verified using wireshark the server has sent back the response as 06 02 b3 43 4f b3 30 b3 03 8c

Some how I'm reading the last value in correctly. Is there some issue with the reading stream?

EDIT

Rest of the response is read correctly but the last character should be 8c But is read as 0152Hex

Response from server : 06 02 b3 43 4f b3 30 b3 03 8c

Read by program : [0006, 0002, 00b3, 0043, 004f, 00b3, 0030, 00b3, 0003, 0152]

issue with reading the last character

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]

Thanks

Rachita Nanda
  • 4,509
  • 9
  • 42
  • 66
  • Have you tried directly inspecting the bytesRead, without converting to String and back? Maybe its just an encoding issue. – Henk De Boer Jan 20 '16 at 14:33
  • @HenkDeBoer I have posted the byte arrat aswell. – Rachita Nanda Jan 21 '16 at 10:44
  • In 8-bit arithmetic, hex 8C and decimal -116 are the same value. So you read the right value, you just converted it to the wrong representation. – David Schwartz Jan 21 '16 at 11:00
  • @DavidSchwartz can you please explain how should I convert ? I'm new to these concepts . – Rachita Nanda Jan 21 '16 at 11:02
  • @RachitaNanda It's not clear what you are trying to do. Also, your code can't produce the output you show. So it's hard for me to tell exactly what the issue is. But as a start, stop converting into and through signed types. – David Schwartz Jan 21 '16 at 11:03
  • @DavidSchwartz can you please suggest alternate methods that do not involve signed types. Thank you – Rachita Nanda Jan 21 '16 at 11:08
  • So the byte array shows 9 values, but the server sent 10? Are you sure you arent counting TCP status codes with wireshark aswell? – Henk De Boer Jan 21 '16 at 11:26
  • @DavidSchwartz I have update my code and output , the input is recieved in 2 packets.Please see – Rachita Nanda Jan 21 '16 at 11:35
  • Can you try doing (char c=(char)(b&0xFF);) instead of (char c=(char)b;). And then print the char c. – Henk De Boer Jan 21 '16 at 11:37
  • @RachitaNanda You read the right value, -116 decimal. You borked it after that, somehow turning it into 152 hex. – David Schwartz Jan 21 '16 at 11:43
  • @HenkDeBoer I changed the char arr using (char c=(char)(b&0xFF); and now I get the correct response. Can you please share why this needs to be done .Thanks a lot – Rachita Nanda Jan 22 '16 at 06:24

1 Answers1

1

The problem in this question was a matter of signed variables versus unsigned variables. When you have a number in computer memory, it is represented by a bunch of bits, each of them 0 or 1. Bytes are generally 8 bits, shorts are 16 etc. In an unsigned number, 8 bits will get you from positive 0 to 255, but not to negative numbers.

This is where signed numbers come in. In a signed number, the first bit tells you whether the following bits represent a negative or positive value. So now you can use 8 bits to represent -128 to +127. (Notice that the positive range is halved, from 255 to 127, because you "sacrifice" half of your range to the negative numbers).

So now what happens if you convert signed to unsigned? Depending on how you do it, things can go wrong. In the problem above, the code char c=(char)b; was converting a signed byte to an unsigned char. The proper way to do this is to "make your byte unsigned" before converting it to a char. You can do that like this: char c=(char)(b&0xFF); more info on casting a byte here.

Essentially, you can just remember that except for char, all java numbers are signed, and all you need to do is paste the &0xFF to make it work for a byte, 0xFFFF to make it work for a short, etc.

The details about why this works are as follows. Calling & means a bitwise and, and 0xFF is hexadecimal for 255. 255 is above the limit of a signed byte (127), so the number b&0xFF gets upgraded to a short by java. However, the short signed bit is on bit 16, while the byte signed bit is on bit 8. So now the byte signed bit becomes a normal 'data' bit in the short, and so the sign of your byte is essentially discarded.

If you do a normal cast, java recognizes that doing direct bitconversion like above would mean that you lose the sign, and java expects you don't like that (at least, that is my assumption), so it preserves the sign for you. So if this isn't what you want, you explicitly tell java what to do.

Community
  • 1
  • 1
Henk De Boer
  • 373
  • 2
  • 6