Suppose there is already written, unchangeable host program, that receives such C++ struct by socket:
#pragma pack(push, 2)
struct Data {
double x;
double y;
double z;
long frameNumber;
};
#pragma pack(pop)
platform: C++ / 32-bit Windows Application compiled in Visual Studio 2008
How to send such data from Java Socket? I have attemted to fill ByteBuffer with putDouble(), and putLong(), also putInt() assuming long as 32-bit, but i cannot produce valid values.
I have also generated and sended data randomly, and structure-level bytes assignment looks fine(I can randomize only one value, for example X), but I cannot produce exact value (propably different double representation?), but only random stuff by sending Math.random() * Double.MAX_VALUE;
Can I use Google Protocol Buffers on only one side (client producing data) to solve this problem?
remember, I cannot change the server (receiving) side
I know that I can move sending data to C++ and use JNI, but I'm searching for simpler solution.
I see at least 2 possible problems here:
What those things look in Java in C++?
In several hours I will provide exact sample data for "byte-hacking" (exact Java value before send and value of received double in C++)
About server bad-design answering
I know that such implemented and unchangeable server is bad software, but the environment in this problem is to inject some data to small old application at "hobbistic-level"
Java representation
Maybe this would help some bits-level C++ expert:
Long.toBinaryString( Double.doubleToRawLongBits( (double) 0 ) );
// 000000000000000000000000000000000000000000000000000000000000000
Long.toBinaryString( Double.doubleToRawLongBits( 1 ) );
// 011111111110000000000000000000000000000000000000000000000000000
Long.toBinaryString( Double.doubleToRawLongBits( 1.1 ) );
// 011111111110001100110011001100110011001100110011001100110011010
Long.toBinaryString( Double.doubleToRawLongBits( 1024 ) );
// 100000010010000000000000000000000000000000000000000000000000000
Long.toBinaryString( Double.doubleToRawLongBits( 1024.1024 ) );
// 100000010010000000000000110100011011011100010111010110001110001
Long.toBinaryString( Double.doubleToRawLongBits( Double.MAX_VALUE ) );
// 111111111101111111111111111111111111111111111111111111111111111
Suppose there is already written, unchangeable host program, that receives such C++ struct by socket
Then you already have a major problem which some unknown person has kindly left you as a legacy. You now have to produce Java code to conform to a specific C++ compiler's conception of the wire format of a specific struct
, which depends on:
I strongly suggest to you that you take the opportunity to fix the whole megillah and define a proper wire format for the transaction.
Once you've done that you can emulate it easily enough with the facilities of DataOutputStream
, or if the problem is even worse and endian-ness is involved, NIO plus ByteBuffer.
I figured it out. Int value is sent fine (propably, can't check this 100% sure in host program), the problem is with doubles endian. You need to convert doubles before send:
public static double changeEndian( double x ) {
ByteBuffer cv = ByteBuffer.allocate( 8 ).putDouble( x );
cv.order( ByteOrder.LITTLE_ENDIAN );
cv.rewind();
return cv.getDouble();
}
And use ByteBufer with putDouble()/putInt().
You'll need to verify the encoding used for double (usually an IEEE standard, but it doesn't have to be) as well as long (big vs little endian) on the platform with the server. You'll also need to identify any padding involved as well.
Then you'll need to manually construct the binary values appropriate to send if they aren't java native encodings. This can be non-trivial, especially for the floating point values, if you are on a pretty messed up server platform.
Also, track down the person who decided to use an implicit binary protocol for the server you can't change and use rubber-hose cryptanalysis on them:
http://en.wikipedia.org/wiki/Rubber-hose_cryptanalysis
There's no easy way to do it, without knowing all the details about the server's platform.
Java has a standard representation for floats and ints across all platforms, but c++ does not define those things. It is platform/architecture specific for c++.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With