Message hexadécimal mutilé via socket
Question
J'essaie de passer un message hexadécimal d'un serveur C à un client Java. La communication fonctionne. Mais la valeur hexagonale que j'obtiens sur le client Java semble être ajoutée avec "FF". Pourquoi cela arrive-t-il?
Du côté C, lorsque j'imprime les octets que je veux envoyer (en hexadécimal), ils semblent corrects.
Veuillez consulter le code ci-dessous:
C serveur 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);
}
Sortie: valeur du tampon Len = -36 [5] = 0 tampon [6] = 0xfffffffdc
ACTUALISÉ
Voici ma sortie WireShark (c'est ce que C Server pousse au client Java):
Notez qu'à la ligne 5 "00 DC" correspond à Datalen = 220 qui doit être stocké en tant que tel dans Len sur le client Java. Il y a donc clairement une erreur sur le client Java. Comme vous l'avez tous mentionné, je peux utiliser Integer.tohexString (((int) buffer [index]) & 0xff) pour l'impression. Mais j'ai besoin de stocker le réseau d'octets avec les valeurs hexagonales correctes. Veuillez aider
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<.
La solution
Votre première étape dans cette situation devrait être de voir ce qui est envoyé "sur le fil". Si vous le pouvez, envisagez d'utiliser Wireshark ou tcpdump pour voir ce qui est transmis. De cette façon, vous pouvez comprendre ce qui ne fonctionne pas comme prévu. Les deux peuvent surveiller les sockets liés aux IPs locaux ainsi qu'aux prises de boucle.
Mais à première vue, je conviendrais qu'il y a un affrontement signé / non signé en cours.
Si vous avez cette sortie, il serait utile de déterminer "qui" est en faute.
Mise à jour:
Comme cela a été mentionné, vous voudrez masquer et utiliser uniquement les 8 bits les plus bas et cela peut être fait par:
b = b & 0xFF
Vous pouvez introduire cela dans votre code de deux manières, l'un consulte une fonction statique simple que vous appelleriez pour chaque octet, par exemple
public static int mask(int rawbyte)
{
return (rawbyte & 0xFF);
}
L'autre est une fonction de wrapper pour datainputStream.read () qui lirait les octets dans un tampon, puis les masquerait tous. Cela pourrait ressembler à quelque chose:
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;
}
Si vous choisissez la première façon, vous voudriez appeler Mask () sur n'importe quelle valeur tampon [] que vous utilisez. Alors
len |= buffer[5];
serait
len |= mask(buffer[5]);
Si vous choisissez la deuxième voie, vous changeriez de tampon à partir d'un tableau d'octet de type à Int:
buffer = new int[...]
Et pourrait mettre à jour votre boucle while sur quelque chose comme:
while( (bytes = socket_read(dis, buffer, 0, 40)) != -1)
Mais cela étant dit ...
Une meilleure option que l'un ou l'autre est d'utiliser Méthode ReadUnSignedByte de DataNutStream.
Vous auriez besoin de retirer 40 octets du flux à la fois vous-même, mais il serait beaucoup plus clair ce que vous faisiez plutôt que de mordre. Ce serait l'approche préférée à mon avis.
Autres conseils
Les octets en Java sont signés. Ainsi, chaque valeur qui a l'ensemble de bits le plus significatif est une valeur négative. Lorsqu'il est converti en un entier qui se produit lorsque vous appelez Integer.Tohexstring Le signe est étendu. Donc, s'il était 10000000B, il deviendra 11111111111111111111110000000b ou 0xffffff80 au lieu de 0x80. Parce que c'est la même valeur négative en 32 bits. Action
Integer.toHexString(((int)buffer[index]) & 0xFF)
Devrait le réparer.
BTW, Java n'a pas de types non signés.
But the hex value that I get on Java client seems to be appended with "FF"
Integer.toHexString(buffer[index] & 0xFF )
résoudra votre problème.
Cela ressemble à une propagation du bit de signe. Len et d'autres variables Java ressemblent à la signée alors qu'ils ne le devraient pas.