How to convert hexadecimal to decimal received per socket

I need to convert a hexadecimal input in the client, to decimal, but I did not find information on how to do this.

Socket server example:

byte[] HEXA = {(byte)0x00, (byte)0x96, (byte)0x07, (byte)0xBF};

ServerSocket serverSocket = null;
Socket client = null;
PrintStream out = null;

try {
    ServerSocket serverSocket = new ServerSocket(9090, 0, InetAddress.getByName(null));
    System.out.println("SOCKET ABERTO");

    client = serverSocket.accept();

    out = new PrintStream(client.getOutputStream());

    out.print(HEXA);
} catch (UnknownHostException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}finally{
    out.close();
    client.close();
    serverSocket.close();
}

On the client side, I need to convert each hexa byte, to decimal (00 150 07 191). I tried using InputStream and BufferedReader, but got no results trying to do the conversion.

Author: hkotsubo, 2020-08-23

1 answers

Server

When you call the method print of a PrintStream passing an array of bytes, it ends up calling this version of the method , which according to the documentation writes the result of String.valueOf(objeto). And what happens when we do this with an array?

byte[] HEXA = { (byte) 0x00, (byte) 0x96, (byte) 0x07, (byte) 0xBF };
System.out.println(String.valueOf(HEXA)); // [B@15db9742

It prints something like "[B@15db9742" (numbers and Letters may vary, as this is the hashcode of the array in question, as explained here). So in fact you are not sending the bytes of the array HEXA, and instead the characters that correspond to the return of String.valueOf (which will be this "code" there).

Actually the very System.out it is a PrintStream, so we can test this behavior by doing System.out.print(HEXA), which will produce the same result. This is all to say that using PrintStream::print may not be what you need.


For your example, you are not working with text / characters, but with "raw" bytes, so to send these bytes you could use a java.io.DataOutputStream and your method write, passing the byte array directly (I recommend reading here and here for more details).

And if you are using Java > = 7, you can also use try-with-resources, which already closes resources automatically, without the need for a block finally:

// Server
byte[] HEXA = { (byte) 0x00, (byte) 0x96, (byte) 0x07, (byte) 0xBF };

try (ServerSocket serverSocket = new ServerSocket(9090, 0, InetAddress.getByName(null))) {
    System.out.println("SOCKET ABERTO");
    Socket client = serverSocket.accept();

    // enviando os bytes para o client
    try (OutputStream out = new DataOutputStream(client.getOutputStream())) {
        out.write(HEXA, 0, HEXA.length);
    } catch (etc...) {
        // mensagens de erro
    } // não precisa de finally, recursos são fechados automaticamente
} catch (etc...) {
    // mensagens de erro
} // não precisa de finally, recursos são fechados automaticamente

Of course if you want, you can also use a BufferedOutputStream, that depending on the case can bring benefits :

try (OutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()))) {
    out.write(HEXA, 0, HEXA.length);
} catch (IOException e) {
    etc...
}

Client

Now to read these bytes, it is worth explaining some details first.

A byte in Java is a numeric type, which uses 8 bits and is signed, that is, it accepts positive and negative values - to be more precise, values between -128 and 127.

Internally, what it has is just bits, and the value is not hexadecimal, not decimal, nothing like that. A byte is a byte (a set of 8 bits). Point.

When we print a byte, then it is shown in some way (be it base 10, 16, 8, 2, or whatever). But this is just a representation of the value, not the value itself.

Think of a number-for example, 2 - as a concept: the idea of a certain quantity ("two things"). I can represent this idea - this value - in different ways: as the digit 2, as 2.0 (or 2,0), as the word "two", "two", and many other formats. Each of these forms is different, but they all represent the same value.

Similarly, when you use a literal like 0xBF in your code, this is just a notation of the language: a form it defined for you to put a hexadecimal number in your code (if you put only BF, it could be confused with a variable/class/method name, for example, then the 0x in front indicates that BF should be interpreted as a number in base 16). But this does not want say that the value of the variable will be in hexadecimal, since internally it will all be converted to bits.

So much so that if you do:

// colocando os valores em hexadecimal
byte[] hex = { (byte) 0x00, (byte) 0x96, (byte) 0x07, (byte) 0xBF };
System.out.println("HEXA:");
for (int i = 0; i < hex.length; i++) {
    byte b = hex[i];
    System.out.printf("hexa: %02X, oct: %03o dec: %04d, dec 'unsigned':%04d, bin: %s\n",
                      b, b, b, b & 0xff, Integer.toBinaryString(b & 0xff));
}

// colocando os valores em decimal
byte[] dec = { (byte) 0, (byte) 150, (byte) 7, (byte) 191 };
System.out.println("DEC:");
for (int i = 0; i < dec.length; i++) {
    byte b = dec[i];
    System.out.printf("hexa: %02X, oct: %03o dec: %04d, dec 'unsigned':%04d, bin: %s\n",
                      b, b, b, b & 0xff, Integer.toBinaryString(b & 0xff));
}

The output will be:

HEXA:
hexa: 00, oct: 000 dec: 0000, dec 'unsigned':0000, bin: 0
hexa: 96, oct: 226 dec: -106, dec 'unsigned':0150, bin: 10010110
hexa: 07, oct: 007 dec: 0007, dec 'unsigned':0007, bin: 111
hexa: BF, oct: 277 dec: -065, dec 'unsigned':0191, bin: 10111111
DEC:
hexa: 00, oct: 000 dec: 0000, dec 'unsigned':0000, bin: 0
hexa: 96, oct: 226 dec: -106, dec 'unsigned':0150, bin: 10010110
hexa: 07, oct: 007 dec: 0007, dec 'unsigned':0007, bin: 111
hexa: BF, oct: 277 dec: -065, dec 'unsigned':0191, bin: 10111111

The values that are in both the hex and dec arrays are exactly the same. The difference is that in the first case I used hexadecimal notation, and in the second I used decimal notation. But the resulting bytes are exactly the same (they are the same values, I just used different representations of these same values to create the arrays).

Notice also how I show the same values (the same bytes) in different ways:

  • on base 16
  • in base 8
  • in base 10 (and values greater than 127 saw negative numbers because byte is a type signed - to better understand, read here )
  • in base 10, but using a" trick " described here and here to convert it to a int and so on have the positive value corresponding to its bits
  • in base 2, using the same "trick" of the case above, to see the bits of the number

As I said, all these forms are different representations of the same bits (of the same values). The final result (the" text "or" the digits/characters " we see on the screen) may be different for each case (96, or 226, or -106, etc), but they all represent the same value (the same byte, the same sequence of 8 bits).

Thus, you do not need to "convert each hex byte to decimal". You just need to read the bytes from the server . That's all.

Then, if you want to show them on the screen in decimal (or any other format), just print them using the code above. Something like this:

// Client
byte[] dados = new byte[1024]; // cria um buffer para ler vários dados de uma vez
try (Socket socket = new Socket(InetAddress.getByName(null), 9090)) {
    InputStream in = new DataInputStream(socket.getInputStream());
    int lidos;
    while ((lidos = in.read(dados)) > 0) { // enquanto tiver dados para ler
        System.out.println("dados lidos do server:");
        for (int i = 0; i < lidos; i++) {
            byte b = dados[i];
            System.out.printf("byte lido - hexa: %02X, dec: %03d\n", b, b & 0xff);
        }
    }
} catch (IOException e) {
    // tratar erros, etc
} // não precisa de finally, recursos são fechados automaticamente

The output will be:

dados lidos do server:
byte lido - hexa: 00, dec: 000
byte lido - hexa: 96, dec: 150
byte lido - hexa: 07, dec: 007
byte lido - hexa: BF, dec: 191

Or, if you want the values as a int:

while ((lidos = in.read(dados)) > 0) {
    for (int i = 0; i < lidos; i++) {
        int x = dados[i] & 0xff;
        System.out.println(x);
    }
}

Which will print:

0
150
7
191

But if you are using Java > = 8, can also use Byte.toUnsignedInt:

while ((lidos = in.read(dados)) > 0) {
    System.out.println("dados lidos do server:");
    for (int i = 0; i < lidos; i++) {
        System.out.println(Byte.toUnsignedInt(dados[i]));
    }
}

Which produces the same result above.

 2
Author: hkotsubo, 2020-08-24 16:35:45