So I been using this method to send data between applications for a long time. I turn everything into a string with delimiters, after that it’s just to use .getBytes and send it on it’s way. When the receiver gets it, I just simply convert the byte array back into a string, and split it, then I just simply convert it back into what it was; Int, long, boolean, and so on. But I like to know, is there a more common/better way of doing it?
For starters: DataOutputStream to write and DataInputStream to read.
Then use that with an OutputStream/InputStream of a TCP Socket.
No need to do toString() or split() or parseInteger(), parseBoolean().
There are more elaborate solutions for sending structures/classes.
In case you want a packet-oriented transport (for example UDP DatagramSocket) you can back the DataOutputStream with a ByteArrayOutputStream and accordingly the DataInputStream with a ByteArrayInputStream.
The BAOS has a reset() method to reset the number of written bytes and thusly allow it to be reused for multiple packets.
Sadly, the BAIS has no such facilities to reuse it, because you cannot make it change the ‘count’ field to specify the number of bytes in the shared byte[] that are valid data. You either need to allocate a separate ByteArrayInputStream for reading subsequent datagram packets or (better) subclass ByteArrayInputStream and simply reset the count and pos fields accordingly for each new datagram packet, like so:
public class ReusableByteArrayInputStream extends ByteArrayInputStream {
public ReusableByteArrayInputStream(byte[] buf) {
super(buf);
}
public void reuse(int length) {
this.count = length;
this.pos = 0;
}
}
Instantiate that class with the byte[] you use for the DatagramPacket and call reuse() whenever you want to read a newly DatagramSocket.receive()'d message.
Edit: this is geared toward UDP (probably obvious).
It depends on what you mean by better(best). If you’re looking for ease of implementation…
public static Packet deserializePacket(DatagramPacket datagram_packet) throws Exception
{
byte[] data = datagram_packet.getData();
ObjectInputStream input_stream = new ObjectInputStream(new ByteArrayInputStream(data));
Packet packet = (Packet) input_stream.readObject();
input_stream.close();
return packet;
}
public static byte[] serializePacket(Packet packet) throws IOException
{
ByteArrayOutputStream array_stream = new ByteArrayOutputStream(MAX_PACKET_SIZE);//1024
ObjectOutputStream output_stream = new ObjectOutputStream(array_stream);
output_stream.writeObject(packet);
byte[] byte_array = array_stream.toByteArray();
output_stream.close();
array_stream.close();
return byte_array;
}
That’s probably what most people are doing, which to be fair is perfectly fine (even great). Something that I noticed though was that there is a TON of overhead added to the packets when call writeObject() and pass in your class.
Which brings us to…
If you’re looking for data compression you’re going to want to be able to deconstruct your objects into it’s individual parts (ints, bools, longs, etc.) and be able to write each of them to a byte array. This means you’ll need to be able to convert an int to a byte and what not. This can save you a ton of space. (I went from 1024byte packets to 31bytes)
Lastly, I noticed that String.getBytes() doesn’t just give you the set of character information; the byte[] is larger than if the just characters are converted to chars. This means that using .getBytes() on all Java objects (that support the functionality) is not a perfect solution to converting to byte[]s (probably contains additional details about the object so it’s rebuilt properly).
what KaiHH said.
life is much easier if you use a byte-array / byteBuffer in the first place.
-
send some data : bb.putInt() bb.putFloat() bb.putOtherThings()
-
read some data : bb.getInt() bb.getFloat() bb.getTheOtherThings()
for strings - life is much easier when they’re not strings but null-terminated-byte-arrays.
o/