Network Protocol Encapsulation

I am working on an application that takes a raw binary message (very simple, the first byte is the type of message, the rest is the payload), and then do something with it. What I'm trying to do is make sure that the network service is distracted from the rest of the application so that you can change the protocol from time to time without affecting the rest of the application too much. The application context is a very simple client-server game, for which I am currently working with a client.

Now I'm a little scared. I need to find an elegant way to just translate the connection into some kind of translator / adapter service that returns beautiful objects (I think). These objects will be thrown into the queue awaiting consumption by the rest of the application. The problem I am facing is more or less this construct (pseudocode):

Suppose each message is 20 bytes, so I can handle the call to this function for every 20 bytes:

public Message GetMessage(byte[] buffer)
{
  switch(buffer[0])
  {
     case 1:
       return Message1(...);
     case 2:
       return Message2(...);
     .....

     case n:
       return MessageN(...);
  }
}

, , , . . , 50 , , switch 50 . , , . , - , , .

!

+3
4

, , . . -

import MyProtocol

handler  = { mListFirmware :  listFirmwareVersions,                  
             mLoadFirmware :  startLoadingFirmwareVersion,
             mLoadFirmwareBl: loadFirmwareVersionBlock, 
             ...
}

...
try {
    handler[message[0]](message[1:])
} catch (NotInTheDictionary e) {
    # complain ...
}

, C/++/#. , . , lambda:

 ...
             mLoadFirmware :  (lambda (m): start_load(m[1:3]); do_threads()),
 ...

, . , . :

 Messages = new Array()

 def listFirmwareVersions(m):
      ...
     Messages.add(Name_Of_This_Method(), This_Method) 
     # it possible to get name of current function in Python or C#

 ... # how to send 
 send_message(Messages.lookup(listFirmwareVersions), ...)

 ... # how to receive
 try {  
     Messages[message[0]](message[1:])
 ...

, :

 class MessageHandler:
      static int message_handlers = [] 
      int msg
      Array data
      void handler
      Message(a_handler):               
          msg = message_handlers.add(this)
          handler = a_handler
      write(Stream s):
          s.write(msg, data)

  listFirmwareVersions = new MessageHandler(do_firmware)
  startLoadingFirmwareVersion = new MessageHandler(load_firmware) 
  ...

 ... # how to send 
 listFirmwareVersions.send(...)

 ... # how to receive
 try {
      message_handlers[message[0]](message[1:])
 ...
+1

Java, . , #. , messageMap:

private final Map<Byte, Class<? extends Message>> messageMap;

Message. addMessage :

public void addMessage(int id, Class<? extends Message> messageClass) {
    messageMap.put((byte) id, messageClass);
}

, , , Message, messageMap, , .

Class<? extends Message> messageClass = messageMap.get(id);
Message                  message      = messageClass.newInstance();

newInstance() .

. , , :

// Messages that we can send to the client.
addOutgoingMessage(0, HeartbeatMessage.class);
addOutgoingMessage(1, BeginMessage    .class);
addOutgoingMessage(2, CancelMessage   .class);

// Messages that the client can send.
addIgnoredMessage (0, HeartbeatMessage.class);
addIncomingMessage(1, StatusMessage   .class, statusMessageHandler);
addIncomingMessage(2, ProgressMessage .class, progressMessageHandler);
addIncomingMessage(3, OutputMessage   .class, outputMessageHandler);
addIncomingMessage(4, FinishedMessage .class, finishedMessageHandler);
addIncomingMessage(5, CancelledMessage.class, cancelledMessageHandler);
addIncomingMessage(6, ErrorMessage    .class, errorMessageHandler);
+2

50 (.. #), , , , . switch.

, : , ( ) , switch, .

+1

#, . , F #, .

, :

member private this.processDefaultGroupMessage(m : Message) =
        try
            match m.Intro.MessageType with
            | (1us) -> this.listFirmwareVersions(m)                               //ListFirmwareVersions              0
            | (2us) -> this.startLoadingFirmwareVersion(m)                        //StartLoadingFirmwareVersion       1
            | (3us) -> this.loadFirmwareVersionBlock(m)                           //LoadFirmwareVersionBlock          2
            | (4us) -> this.removeFirmwareVersion(m)                              //RemoveFirmwareVersion             3
            | (5us) -> this.activateFirmwareVersion(m)                            //ActivateFirmwareVersion           3        
            | (12us) -> this.startLoadingBitmapLibrary(m)                         //StartLoadingBitmapLibrary         2
            | (13us) -> this.loadBitmapBlock(m)                                   //LoadBitmapLibraryBlock            2        
            | (21us) -> this.listFonts(m)                                         //ListFonts                         0
            | (22us) -> this.loadFont(m)                                          //LoadFont                          4
            | (23us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //RemoveFont                        3
            | (24us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //SetDefaultFont                    3         
            | (31us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //ListParameterSets                 0
            | (32us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //LoadParameterSets                 4
            | (33us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //RemoveParameterSet                3
            | (34us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //ActivateParameterSet              3
            | (35us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //GetParameterSet                   3        
            | (41us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //StartSelfTest                     0
            | (42us) -> this.ackResponse(m)                                       //GetStatus (reply with ACK)        0
            | (43us) -> this.getStatusDetail(m)                                   //GetStatusDetail                   0
            | (44us) -> this.resetStatus(m)                                       //ResetStatus                       5
            | (45us) -> this.setDateTime(m)                                       //SetDateTime                       6
            | (46us) -> this.nakResponse(m, VPL_FRAMELENGTH)                      //GetDateTime                       0
            | (71us) -> this.clearConfiguration(m)                                //ClearConfiguration                0
            | (72us) -> this.defineTextFields(m)                                  //DefineTextFields                  11
            | (74us) -> this.defineClockFields(m)                                 //DefineClockFields                 13
            | (80us) -> this.deleteFieldDefinitions(m)                            //DeleteFieldDefinitions            14
            | (91us) -> this.preloadTextFields(m)                                 //PreloadTextFields                 15
            | (94us) -> this.clearFields(m)                                       //ClearFields                       17
            | (95us) -> this.activate(m)                                          //Activate                          0
            | _ -> this.nakResponse(m, VPL_REQUESTNOTSUPPORTED)
        with 
            | _ -> this.nakResponse(m, VPL_INVALID)

, , switch #. , csharp, fsharp.

FYI: :

IDataTransportServer - responsible for receiving data through RS232 or TCP / IP

IDataProcessor - responsible for parsing binary data and turning it into instances of the Message class

IMessageProcessor - responsible for processing messages (this is the fsharp module)

I have no idea if this is useful for you, but I just wanted to tell you how we deal with this problem.

+1
source

Source: https://habr.com/ru/post/1710851/


All Articles