Mensagem hexadecimal mutilada via soquete
Pergunta
Estou tentando passar uma mensagem hexadecimal de um servidor C para um cliente Java. A comunicação funciona.Mas o valor hexadecimal que obtenho no cliente Java parece estar anexado com "ff".Por que isso está acontecendo?
No lado C, quando imprimo os bytes que desejo enviar (em Hex), eles parecem ok.
Por favor, veja o código abaixo:
Servidor 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");
}
Cliente 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);
}
Saída: valor de len= -36 buffer [5]= 0 buffer [6]= 0xfffffffdc
ATUALIZADO
Aqui está minha saída do WireShark (isto é o que o servidor C envia para o cliente Java):
Observe que na linha 5 "00 dc" corresponde a datalen= 220 que deve ser armazenado como tal em len no cliente Java.Portanto, há claramente algum erro no cliente Java.Como todos mencionaram, posso usar Integer.toHexString (((int) buffer [index]) & 0xFF) para impressão.Mas preciso armazenar a matriz de bytes com os valores hexadecimais corretos.Por favor ajude
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<.
Solução
Sua primeira etapa nessa situação deve ser ver o que está sendo enviado "através da transferência". Se você puder, considere usar fioshark ou tcpdump para ver o que está sendo transmitido. Dessa forma, você pode descobrir o que não está funcionando conforme o esperado. Ambos podem monitorar soquetes vinculados a IPs locais, bem como soquetes de loopback.
Mas ao que parece, eu concordaria que há um conflito assinado / não assinado em andamento.
Se você tiver esta saída, seria útil para determinar "quem" é o culpado.
<"Atualizar:
Como foi mencionado, você desejará remover a máscara e usar apenas os 8 bits mais baixos e isso pode ser feito por:
b = b & 0xFF
Você pode introduzir isso em seu código de duas maneiras, uma é por meio de uma função estática simples que você chamaria para cada byte, por exemplo,
public static int mask(int rawbyte)
{
return (rawbyte & 0xFF);
}
A outra é uma função de wrapper para DataInputStream.read () que lê os bytes em um buffer e, em seguida, mascara todos eles. Pode ser algo como:
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 você escolher a primeira maneira, deverá chamar mask () em qualquer valor buffer [] que usar. Então,
len |= buffer[5];
seria
len |= mask(buffer[5]);
Se você escolher a segunda maneira, deverá alterar o buffer de uma matriz do tipo byte para int:
buffer = new int[...]
e poderia atualizar seu loop while para algo como:
while( (bytes = socket_read(dis, buffer, 0, 40)) != -1)
Mas dito isso ...
Uma opção melhor do que qualquer uma dessas é usar Método readUnsignedByte de DataInputStream .
Você mesmo precisaria retirar 40 bytes do fluxo de cada vez, mas ficaria muito mais claro o que você estava fazendo ao invés de mexer um pouco. Essa seria a abordagem preferida na minha opinião.
Outras dicas
Os bytes em java são assinados.Portanto, cada valor que possui o conjunto de bits mais significativo é um valor negativo.Quando ele é convertido para um inteiro, o que acontece quando você chama Integer.toHexString, o sinal é estendido.Portanto, se fosse 10000000b, ele se tornaria 1111111111111111111111111110000000b ou 0xFFFFFF80 em vez de 0x80.Porque esse é o mesmo valor negativo em 32 bits.Fazendo
Integer.toHexString(((int)buffer[index]) & 0xFF)
Deve consertar.
A propósito, java não tem tipos não assinados.
But the hex value that I get on Java client seems to be appended with "FF"
Integer.toHexString(buffer[index] & 0xFF )
resolverá o seu problema.
Parece propagação de bit de sinal.len e outras variáveis JAVA parecem assinadas, mas não deveriam.