Mangled Hex message via socket
I am trying to pass a hex message from a C server to a Java client. The communication works. But the hex value that I get on Java client seems to be appended with "ff". Why is this happening?
At the C side,when I print the bytes I want to send(in Hex), they seem ok.
Please see the code below:
C server:
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");
}
Java Client:
while( (bytes =dis.read(buffer, 0, 40)) != -1){
for(int index=38; index >= 0; index--) {
System.out.println("index ="+i开发者_运维技巧ndex);
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);
}
OutPut: value of len= -36 buffer[5]=0 buffer[6]= 0xfffffffdc
UPDATED
Here is my wireshark output(This is what C server pushes to Java Client):
Note that at row 5 "00 dc" corresponds to datalen= 220 which should be stored as such in len on Java client. So there is clearly some error on the Java Client. Like you have all mentioned, I can use Integer.toHexString(((int)buffer[index]) & 0xFF) for printing. But I need to store the byte array with the correct hex values. Please help
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<.
The bytes in java are signed. So each value that has the most significant bit set is a negative value. When it is converted to an integer which happens when you call Integer.toHexString the sign is extended. So if it was 10000000b it will become 11111111111111111111111110000000b or 0xFFFFFF80 instead of 0x80. Because that is the same negative value in 32 bits. Doing
Integer.toHexString(((int)buffer[index]) & 0xFF)
Should fix it.
BTW, java has no unsigned types.
But the hex value that I get on Java client seems to be appended with "FF"
Integer.toHexString(buffer[index] & 0xFF )
will fix your issue.
Your first step in these situation should be to see what is being sent "over the wire". If you are able, consider using wireshark or tcpdump to see what is being transmitted. That way, you can figure out what is not working as expected. Both can monitor sockets bound to local IPs as well as loopback sockets.
But from the looks of it, I would agree that there is a signed/unsigned clash going on.
If you have this output, it would be helpful in determining "who" is at fault.
Update:
As has been mentioned, you will want to mask off and use only the lowest 8 bits and this can be done by:
b = b & 0xFF
You could introduce this into your code two ways, one is through a simple static function that you would call for each byte, e.g.
public static int mask(int rawbyte)
{
return (rawbyte & 0xFF);
}
The other is a wrapper function for DataInputStream.read() that would read the bytes into a buffer, and then mask them all. It might look something like:
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;
}
If you chose the first way, you would want to call mask() on any buffer[] value you use. So
len |= buffer[5];
would be
len |= mask(buffer[5]);
If you chose the second way, then you would change buffer from an array of type byte to int:
buffer = new int[...]
and could update your while loop to something like:
while( (bytes = socket_read(dis, buffer, 0, 40)) != -1)
But that being said...
A better option than either of these is to make use of DataInputStream's readUnsignedByte method.
You would need to pull 40 bytes off of the stream at a time yourself, but it would be much more clear what you were doing rather than bit twiddling. This would be the preferred approach in my opinion.
Sounds like sign bit propagation. len and other JAVA variable looks like signed when they should not.
精彩评论