1

I want to implement an existing protocol (server side only) in Java. The client is an old game client that I would like to write a server for.

The protocol is structured like this:

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+----//----+--------+--------+
| size0  | size1  |  seq0  |  seq1  | sessID0| sessID1| param0 | param1 |   id0  |   id1  |  payload | trash  | trash  |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+----//----+--------+--------+

Now the protocol, being pretty old, defines many versions, where the header (up until including id1) stays the same (as do the last two padding bytes).

The payload varies from version to version, so it needs to be decoded differently. See simplified example below (pl# for payload byte number):

Version 1.00    
    ...+--------+--------+--------+--------+--------+--------/--------+--------+...
(HEAD) |  pl0   |  pl1   |  pl2   |  pl3   |  pl4   |  pl5  ...  pl22 |  pl23  |
    ...+--------+--------+--------+--------+--------+--------/--------+--------+...
       | clientVersion (little endian)     | userName (fixed String l=20)      |
    ...+--------+--------+--------+--------+--------+--------/--------+--------+


Version 1.10
    ...+--------+--------+--------+--------+--------+--------/--------+--------+...
(HEAD) |  pl0   |  pl1   |  pl2   |  pl3   |  pl4   |  pl5  ... plN-1 |  plN   |
    ...+--------+--------+--------+--------+--------+--------/--------+--------+...
       | clientVersion (big endian)        | userName (pascal String)          |
    ...+--------+--------+--------+--------+--------+--------/--------+--------+

The question for me now is two-fold.

First and foremost, how do you implement such a protocol without getting into switch() hell? I have read that a lot of people recommend a FSM (or maybe State-pattern) for that, but I didn't get how this should work. I have also been looking into (and playing with) Google's ProtoBuf, which sadly does not support any int16 / uint16 data types.

Secondly, how to implement this, so that I end up with a nice, clean PacketHandler-interface that may look like this:

public interface PacketHandler {

    void onLoginRequest(Client client, LoginRequest request);
    void onHeartbeatRequest(Client client, HeartbeatRequest request);
    ...

}

The purpose of that Handler would be that the classes LoginRequest and HeartbeatRequest are the same, no matter the client version.

On the outgoing side of things I want to be able to write these kind of POJOs as well, for example:

public class PacketHandlerImpl implements PacketHandler {

    void onLoginRequest(Client client, LoginRequest request) {
        if(success)
            client.send(new LoginGrantedResponse(...));
        else
            client.send(new LoginDeniedResponse(...));
    }
    ...

}

Thanks in advance for your help!

baeda
  • 189
  • 12
  • One way is to write custom (de)serialization logic for packets, so Java serialization framework will do significant part of job for you. Or consider faster option using JDK `Externalizable`. See this SO question: http://stackoverflow.com/questions/817853/what-is-the-difference-between-serializable-and-externalizable-in-java – Victor Sorokin Jan 19 '15 at 14:24
  • @VictorSorokin And how would I react to the different kinds of client versions with serialization? I mean when I (de-)serialize I am stuck with the same (un-)marshalling logic, no? – baeda Jan 19 '15 at 14:27
  • I assume, your protocol has fixed layout prefix you can use to deduce version. If this is true, your marshalling logic can branch out to correct deserialization code. I guess, need to branch inside marshalling code means you need `Externalizable`, not `Serializable`. – Victor Sorokin Jan 19 '15 at 14:33
  • If you are implementing server for tcpi protocol, Apache MINA https://mina.apache.org couls be good starting point. Handles socket connections, buffering, fram borders etc. And transport, protocol and logic can be on separate layers. – ikettu Jan 19 '15 at 15:05

0 Answers0