Messaggio esadecimale alterato tramite socket
Domanda
Sto cercando di passare un messaggio esadecimale da un server C a un client Java. La comunicazione funziona.Ma il valore esadecimale che ottengo sul client Java sembra essere aggiunto con "ff".Perché sta succedendo?
Sul lato C, quando stampo i byte che voglio inviare (in Hex), sembrano a posto.
Vedere il codice di seguito:
Server C:
int datalen = 220;
/* create outgoing message */
idx = 0;
en_outmsg[idx++] = FEB & 0xFF;
en_outmsg[idx++] = ENT & 0xFF;
en_outmsg[idx++] = CBA & 0xFF;
en_outmsg[idx++] = GRP & 0xFF;
en_outmsg[idx++] = OUTGOING & 0xFF;
en_outmsg[idx++] = (datalen & 0xFF00) >> 8;
en_outmsg[idx++] = datalen & 0xFF;
for(i= 0; i<39; i++){
printf("en_outmsg[%d] to send = %x\n",i, en_outmsg[i]);
}
en_outmsg[i+1] = '\n';
if (send(connected, en_outmsg, 40, 0) > 0)
{
printf("sending over\n");
}
Client Java:
while( (bytes =dis.read(buffer, 0, 40)) != -1){
for(int index=38; index >= 0; index--) {
System.out.println("index ="+index);
System.out.println("buffer ="+Integer.toHexString(buffer[index]));
}
System.out.println("bytes="+bytes);
len = 0;
len |= buffer[5];
len = len << 8;
len |= buffer[6];
System.out.println("value of len= "+len);
}
Uscita: valore di len= -36 buffer [5]= 0 buffer [6]= 0xfffffffdc
AGGIORNATO
Ecco il mio output di WireShark (questo è ciò che il server C invia al client Java):
Notare che alla riga 5 "00 dc" corrisponde a datalen= 220 che dovrebbe essere memorizzato come tale in len sul client Java.Quindi c'è chiaramente qualche errore sul client Java.Come tutti voi avete detto, posso usare Integer.toHexString (((int) buffer [index]) & 0xFF) per la stampa.Ma ho bisogno di memorizzare l'array di byte con i valori esadecimali corretti.Per favore aiutatemi
0000 00 00 03 04 00 06 00 00 00 00 00 00 00 00 08 00 ........ ........
0010 45 00 00 5c b4 75 40 00 40 06 a0 ac c0 a8 b2 14 E..\.u@. @.......
0020 c0 a8 b2 14 09 60 b7 bb fe bd 3a 2d fe 36 cc 8c .....`.. ..:-.6..
0030 80 18 02 20 e5 c8 00 00 01 01 08 0a 00 04 8e 5f ... .... ......._
0040 00 04 8e 5f 0a 01 01 16 01 00 dc 00 01 02 03 04 ..._.... ........
0050 05 06 07 08 09 0a 0b 0c 0d 0e 0f 2b 7e 15 16 28 ........ ...+~..(
0060 ae d2 a6 ab f7 15 88 09 cf 4f 3c d0 ........ .O<.
Soluzione
Il primo passo in queste situazioni dovrebbe essere vedere cosa viene inviato "via cavo". Se puoi, considera l'utilizzo di wirehark o tcpdump per vedere cosa viene trasmesso. In questo modo, puoi capire cosa non funziona come previsto. Entrambi possono monitorare i socket associati a IP locali così come i socket di loopback.
Ma a quanto pare, sono d'accordo sul fatto che sia in corso uno scontro firmato / non firmato.
Se hai questo output, sarebbe utile per determinare "chi" è in colpa.
<⇨Update:
Come è stato detto, dovrai mascherare e utilizzare solo gli 8 bit più bassi e questo può essere fatto:
b = b & 0xFF
Puoi introdurlo nel tuo codice in due modi, uno è attraverso una semplice funzione statica che chiameresti per ogni byte, ad esempio
public static int mask(int rawbyte)
{
return (rawbyte & 0xFF);
}
L'altra è una funzione wrapper per DataInputStream.read () che legge i byte in un buffer e poi li maschera tutti. Potrebbe avere un aspetto simile a:
public static int socket_read(DataInputStream dis, int arr[], int off, int len)
{
b = new byte[len];
int rv = dis.read(b, off, len);
for(int i=0; i < len; i++)
{
arr[i] = ((int)b[i]) & 0xFF;
}
return rv;
}
Se scegli il primo modo, dovresti chiamare mask () su qualsiasi valore di buffer [] che usi. Quindi
len |= buffer[5];
sarebbe
len |= mask(buffer[5]);
Se scegli il secondo modo, cambierai il buffer da un array di tipo byte a int:
buffer = new int[...]
e potrebbe aggiornare il tuo ciclo while a qualcosa del tipo:
while( (bytes = socket_read(dis, buffer, 0, 40)) != -1)
Ma detto questo ...
Un'opzione migliore di entrambe è quella di utilizzare metodo readUnsignedByte di DataInputStream .
Avresti bisogno di estrarre dallo stream 40 byte alla volta, ma sarebbe molto più chiaro cosa stavi facendo piuttosto che giocherellare un po '. Questo sarebbe l'approccio preferito a mio parere.
Altri suggerimenti
I byte in java sono firmati.Quindi ogni valore che ha il bit più significativo impostato è un valore negativo.Quando viene convertito in un numero intero, cosa che accade quando chiami Integer.toHexString, il segno viene esteso.Quindi, se era 10000000b, diventerà 11111111111111111111111110000000b o 0xFFFFFF80 invece di 0x80.Perché questo è lo stesso valore negativo a 32 bit.In corso
Integer.toHexString(((int)buffer[index]) & 0xFF)
Dovrebbe risolverlo.
BTW, java non ha tipi senza segno.
But the hex value that I get on Java client seems to be appended with "FF"
Integer.toHexString(buffer[index] & 0xFF )
risolverà il tuo problema.
Sembra una propagazione dei bit di segno.len e altre variabili JAVA sembrano firmate quando non dovrebbero.