I'm writing a .NET application that will make an RPC call to a Java application (via a message queue). The data sent in both directions will be large arrays of floating-point numbers. What is the best way to serialize them to send them across the wire? I'd like something more compact than text, but architecture-independent as the server may not be an x86 machine. The Java application can be changed as needed.
Text is really the only platform independent way to represent floating point numbers, and its certainly the easiest to do. If you are concerned about message size, you could always GZip your messages.
I'm currently reading about Protocol Buffers and they look promising. There is an official Google implementation for Java and a C# port of it by none other than Jon Skeet.
Java numeric primitives actually are stored (in the JVM) and written (via jnava.io.DataOutputStream
and java.nio.ByteBuffer
) in network order and the floating point values are IEEE standard. They are directly interchangeable with C#/.NET. Well, if .NET provided network byte order to read doubles (see below for code).
So, you can send and receive any primitive using the two classes mentioned here (and the input counterparts) as long as the .NET side is reading/writing in network byte order as you should always use.
Java side for example:
// Assume the following somewhere in your class
Socket socket;
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// Send a double
out.writeDouble(doubleValue);
C# side to retrieve the value:
Stream stream = new NetworkStream(socket, FileAccess.ReadWrite, true);
BinaryReader reader = new BinaryReader(stream, Encoding.UTF8);
// Read double from the stream
long v = IPAddress.NetworkToHostOrder(reader.ReadInt64());
double doubleValue = BitConverter.Int64BitsToDouble(v);
For writing you do the opposite, C# has to write in network byte order.
Stream stream = new NetworkStream(socket, FileAccess.ReadWrite, true);
BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8);
// Write double to the stream
long v = BitConverter.DoubleToInt64Bits(doubleValue);
writer.Write(IPAddress.HostToNetworkOrder(v));
And then on the Java side to read these back in:
// Some where in your class
Socket socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
// To read the double
double doubleValue = in.readDouble();
The C# IPAddress
class provides network byte order reading/writing methods for all primitives except double and float, but as in my example you can pass through through either a 32-bit or 64-bit int respectively.