Basically RMI helps developers going through a difficult time in programming network by offering simplified function call format (defining message structure, send message, and receive message). Thus RMI not only shortens the development time but also reduces mistakes as making network send/receive routine.
4.1Example of program not using RMI
// Message header ID definitions #define Message_Knight_Move_ID 12 #define Message_Knight_Attack_ID 13 // Message format definitions struct Message { int m_msgID; }; struct Message_Knight_Move:public Message { int m_id; float m_x,m_y,m_z; }; struct Message_Knight_Attack:public Message { int m_id; int m_target; int m_damage; }; // A function which send a formatted message void Knight_Move(int id,float x,float y,float z) { Message_Knight_Move msg; msg.m_msgID=Message_Knight_Move_ID; msg.m_id=id; msg.m_x=x; msg.m_y=y; msg.m_z=z; Send(msg); } // A function which send a formatted message void Knight_Attack(int id,int target,int damage) { Message_Knight_Attack msg; msg.m_msgID=Message_Knight_Attack_ID; msg.m_id=id; msg.m_target=target; msg.m_damage=damage; Send(msg); } // Identified a received message // and call an appropriate function for message handling void DoReceivedMessage(Message* msg) { switch(msg->m_msgID) { case Message_Knight_Move_ID: { Message_Knight_Move* msg2= (Message_Knight_Move*)msg; Do_Knight_Move( msg2->m_id, msg2->m_x, msg2->m_y, msg2->m_z); } break; // ... cases for other message types case Message_Knight_Attack_ID: { Message_Knight_Attack* msg2= (Message_Knight_Attack*)msg; Do_Knight_Attack( msg2->m_id, msg2->m_target, msg2->m_damage); } break; // ... cases for other message types } }
But with the use of RMI, you can simply write a code as shown in below which returns the same result.
Knight_Move([in] int id,[in] float x,[in] float y,[in] float z); Knight_Attack([in] int id,[in] int target,[in] int damage);
The format used in above sample code is IDL(Interface Description Language). If you compile this language then C++ source will be created. The created C++ source files are consisting of structure declaration, send message, receive message and etc. This means that you don't have to make network handling routine by him or herself since PIDL Compiler (ProudNet IDL) generates it automatically for you!
Let's go through some of terms that we should be familiar with. As mentioned earlier, there are files that get generated when compiling IDL file. And there is a module that converts one of function calls among these files into a message and sends it to network. This module is called proxy and a module that analyzes the received message then calls for user function is called stub. For example, if host A calls for RMI function called X, then proxy of X gets called, converts to a network message and gets sent to host B. And host B send the received message to stub, which analyzes the message first and calls for function X written by user.
Eventually, as looking at the surface, it appears as host A just calling for function of host B. And this is why it's named as Remote Method Invocation.
4.2RMI system of ProudNet
The commonly used IDL type or RIM system is simply too heavy and slow that ProudNet has its own custom made Remote Method Invocation (RMI) system which fixes those problems.
In game development, asynchronous RMI, meaning RMIs that don't wait for a returned value of function call, is mostly used. Due to this reason, ProudNet only supports asynchronous RMI.