How to convert hexadecimal to decimal received by socket

Asked

Viewed 114 times

0

I need to convert a hexadecimal entry in the client to decimal, but I couldn’t find information on how to do this.

Example of socket server:

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 did not get results trying to make the conversion.

1 answer

2


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" (the numbers and letters may vary because it is hashcode of the array in question, as explained here). So you’re not actually sending the bytes from the array HEXA, and yes the characters that correspond to the return of String.valueOf (what will be this "code" there).

In fact the very System.out is a PrintStream, then we can test this behavior by doing System.out.print(HEXA), that will produce the same result. This is all to say that using PrintStream::print maybe it’s not 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 (recommend reading here and here for more details).

And if you’re using Java >= 7, you can also use Try-with-Resources, that already closes the 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 before.

A byte in Java is a numerical type, which uses 8 bits and is Signed (with signal), that is, 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, or decimal, nothing like that. A byte is a byte (an 8-bit set). Dot.

When we print a byte, it is shown in some way (either base 10, 16, 8, 2, or whatever). But that’s 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 amount ("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 all represent the same value.

Similarly, when you use in your code a literal like 0xBF, this is just a notation of the language: a form that she set for you to put a hexadecimal number in your code (if you just put BF, could be confused with a variable/class/method name, for example, then the 0x at the front indicates that BF should be interpreted as a number in base 16). But this does not mean that the value of the variable will be in hexadecimal, because internally everything will 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 exit 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 arrays hex and dec 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 (are the same values, I just used different representations of those same values to create the arrays).

Also notice how I show the same values (the same bytes) in different ways:

  • at base 16
  • at base 8
  • base 10 (and values greater than 127 turn negative numbers because byte is a guy Signed - to better understand, read here)
  • on base 10, but using a "trick" described here and here to convert it to a int and thus 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 all represent the same value (the same byte, the same 8-bit sequence).

So you don’t need "convert each hexa byte to decimal". You just need to read the bytes of 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 exit 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);
    }
}

That will print:

0
150
7
191

But if you’re using Java >= 8, you 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.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.