Hello there Zyle,
I would really consider using a library already available out there, maybe MINA and Netty aren't to your liking but it's well worth it not having to deal with all of the network stuff. I would suggest you have a look at
KryoNet which is a networking library built on top of the
Kryo Serialization Library. It offers really nice ways of sending POJO's across the wire.
However if you still insist on writing your own, I'd say you're on the right track, the important thing I'd say is the encoder/decoder of packets. If the first byte in the packet bytearray defines what type of packet you're dealing with the decoder will easily know how to decode it (what things to read and in what order).
In all fairness, Packet could be an interface with a read method and a write method. You would also need a way of registering your classes.
For instance your Packet.java interface could look like this:
import java.nio.ByteBuffer;
public interface Packet {
public void encode(final ByteBuffer byteBuffer);
public void decode(final ByteBuffer byteBuffer);
}
And you could have a packet implementation like this:
import java.nio.ByteBuffer;
public class SimplePacket implements Packet {
private int someInteger;
private float someFloat;
@Override
public void encode(final ByteBuffer byteBuffer) {
byteBuffer.putInt(this.someInteger);
byteBuffer.putFloat(someFloat);
}
@Override
public void decode(final ByteBuffer byteBuffer) {
this.someInteger = byteBuffer.getInt();
this.someFloat = byteBuffer.getFloat();
}
// Setters and getters here
}
Then you might need some sort of converter or similar to translate packets and bytebuffers:
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
public class PacketConverter {
private static Map<Integer, Class<? extends Packet>> packetClasses = new HashMap<Integer, Class<? extends Packet>>();
public synchronized static void registerClass(final Class<? extends Packet> packetClass) {
final int id = packetClasses.size() + 1;
packetClasses.put(id, packetClass);
}
private int getIdForPacketInstance(final Packet packet) {
for (final Map.Entry<Integer, Class<? extends Packet>> entry : packetClasses.entrySet()) {
if (entry.getValue().getName().equals(packet.getClass().getName())) {
return entry.getKey();
}
}
return -1;
}
public ByteBuffer serialize(final Packet packet) {
final int id = getIdForPacketInstance(packet);
if (id != -1) {
final ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.MAX_VALUE);
byteBuffer.putInt(getIdForPacketInstance(packet));
packet.encode(byteBuffer);
byteBuffer.flip();
return byteBuffer;
}
return null;
}
public Packet deserialize(final ByteBuffer byteBuffer) throws Exception {
final int packetId = byteBuffer.getInt();
final Class<? extends Packet> packetClass = packetClasses.get(packetId);
if (packetClass != null) {
final Packet packet = packetClass.newInstance();
packet.decode(byteBuffer);
return packet;
}
return null;
}
}
As you can see the PacketConverter allows you to register packet classes. This model is really similar to the KryoNet model which is why I would suggest you have a look at that first since that would take care of the object serialization for you, sparing you from dealing with the bytebuffers.
Also note that I've not tested this code so there might be issues.
Hope this helps you in some way.
Daniel