RMI Question

  • Follow


I am designing an RMI kind of framework - this is just for learning,
not a real project. This is in C++.

I have Marshalling & Unmarshalling classes in Place for function params.
I am using Boost Message_Queue to transmit the function call & Marshalled
Params from Client to Server.
Currently, there can be only 1 Client Process & 1 Server process at a time.
And currently, the client is single threaded.

Marshal returns a void * buffer, which I can pass through
the message_queue.

I generate a struct which has the following members
- the function id to call
- all the params to be passed.
This structure is Marshalled & sent.

The thing where I am stuck is this
- The server needs to get the pass the size of the buffer to 
message_queue::receive
Now different Marshalled Data has different sizes. So how does the server 
know
what size of buffer to use for recieving the message.

One thing I can think of is this
- I don't include the function id in the Struct.

My function call will then consist of 2 calls
-> First I send the Function Id in the message_queue (this will always be of 
size of int)
-> I build a map in the server as the params size buffer for each Funciton 
ID.
-> Once the server recieves a function id, it then knows the next message 
will be Marshalled
Param Buffer & it knows the size of the buffer corresponding to the function 
call.

But I think this design will not work once I change my client to be 
multi-threaded.
In that case, one thread may send a function id & before the params are 
sent, a
2nd thread in the client may send a different message.

I can think of 2 solutions for this
- Each thread has a different message queue & the server listens on as many 
message_queues
as there are client threads.
- Or I can serialize all client calls - i.e. make the 2 message atomic. Take 
a lock, send the first
message & then the second message & then unlock. This way, each function id 
message will be
followed by the params for that function.

I was wondering what is the general solution adapted by RMI frameworks for 
this?
Is there a better solution?

I am not stuck on message_queues. I can also substitute this by pipes or 
sockets.



0
Reply Newbie 1/28/2010 5:17:06 AM

"Newbie" <n@p.com> writes:

> I am designing an RMI kind of framework - this is just for learning,
> not a real project. This is in C++.
>
> I have Marshalling & Unmarshalling classes in Place for function params.
> I am using Boost Message_Queue to transmit the function call & Marshalled
> Params from Client to Server.
> Currently, there can be only 1 Client Process & 1 Server process at a time.
> And currently, the client is single threaded.
>
> Marshal returns a void * buffer, which I can pass through
> the message_queue.
>
> I generate a struct which has the following members
> - the function id to call
> - all the params to be passed.
> This structure is Marshalled & sent.
>
> The thing where I am stuck is this
> - The server needs to get the pass the size of the buffer to 
> message_queue::receive
> Now different Marshalled Data has different sizes. So how does the server 
> know what size of buffer to use for recieving the message.

Yes.  The error is in using a void* to denoted a buffer.  
What is a buffer?  
It is a definite sequence of bytes, which means that it as a length.

You could use:

typedef unsigned char byte;
typedef std::vector<byte> buffer;

Then it will be easy to write things like:

buffer b;
b.size();
int k;
b[k];
buffer::iterator i=b.begin();
while(i!=b.end()){
    *i;
    i++;
}





> One thing I can think of is this
> - I don't include the function id in the Struct.
>
> My function call will then consist of 2 calls
> -> First I send the Function Id in the message_queue (this will always be of 
> size of int)
> -> I build a map in the server as the params size buffer for each Funciton 
> ID.
> -> Once the server recieves a function id, it then knows the next message 
> will be Marshalled
> Param Buffer & it knows the size of the buffer corresponding to the function 
> call.
>
> But I think this design will not work once I change my client to be 
> multi-threaded.
> In that case, one thread may send a function id & before the params are 
> sent, a
> 2nd thread in the client may send a different message.

In any case, you have to ensure that atomic communication of the messages occur.

On unix, most interfaces DO NOT enforce atomic communications of any
messages bigger than a single byte, so you have to implement this
atomicity yourself.

An easy way to do it is to have a single thread at each ends of the
communication channel, and to let them dispatch the message (thrue
queues or whatever) to other threads.


> I can think of 2 solutions for this
> - Each thread has a different message queue & the server listens on as many 
> message_queues
> as there are client threads.
> - Or I can serialize all client calls - i.e. make the 2 message atomic. Take 
> a lock, send the first
> message & then the second message & then unlock. This way, each function id 
> message will be
> followed by the params for that function.

Of course, it would be much simplier to send as a single message a function call.

typedef struct {
   RemoteThread  t;
   Function      f;
   Arguments     a;
}             FunctionInvocation;


> I was wondering what is the general solution adapted by RMI frameworks for 
> this?
> Is there a better solution?
>
> I am not stuck on message_queues. I can also substitute this by pipes or 
> sockets.

Of course.  As long as you've abstracted away a specializable
interface to do so. 


-- 
__Pascal Bourguignon__
0
Reply pjb 1/28/2010 6:54:40 PM


"Newbie" <n@p.com> wrote in message 
news:hjr6kk$g0k$1@news.eternal-september.org...
>I am designing an RMI kind of framework - this is just for learning,
> not a real project. This is in C++.
>
> I have Marshalling & Unmarshalling classes in Place for function params.
> I am using Boost Message_Queue to transmit the function call & Marshalled
> Params from Client to Server.
> Currently, there can be only 1 Client Process & 1 Server process at a 
> time.
> And currently, the client is single threaded.
>
> Marshal returns a void * buffer, which I can pass through
> the message_queue.
>
> I generate a struct which has the following members
> - the function id to call
> - all the params to be passed.
> This structure is Marshalled & sent.
>
> The thing where I am stuck is this
> - The server needs to get the pass the size of the buffer to 
> message_queue::receive
> Now different Marshalled Data has different sizes. So how does the server 
> know
> what size of buffer to use for recieving the message.
>
> One thing I can think of is this
> - I don't include the function id in the Struct.
>
> My function call will then consist of 2 calls
> -> First I send the Function Id in the message_queue (this will always be 
> of size of int)
> -> I build a map in the server as the params size buffer for each Funciton 
> ID.
> -> Once the server recieves a function id, it then knows the next message 
> will be Marshalled
> Param Buffer & it knows the size of the buffer corresponding to the 
> function call.
>
> But I think this design will not work once I change my client to be 
> multi-threaded.
> In that case, one thread may send a function id & before the params are 
> sent, a
> 2nd thread in the client may send a different message.
>
> I can think of 2 solutions for this
> - Each thread has a different message queue & the server listens on as 
> many message_queues
> as there are client threads.
> - Or I can serialize all client calls - i.e. make the 2 message atomic. 
> Take a lock, send the first
> message & then the second message & then unlock. This way, each function 
> id message will be
> followed by the params for that function.
>
> I was wondering what is the general solution adapted by RMI frameworks for 
> this?
> Is there a better solution?
>
> I am not stuck on message_queues. I can also substitute this by pipes or 
> sockets.
>
>


all this is difficult to understand...

but, anyways:
the use of either signatures or IDL's is a way so that both ends may know 
the size and layout of the args.

for example:
"Foo/Bar(ii)v"
declares the call as:
"void Foo.Bar(int, int);".

in the signature-passing case, the signature is sent as a part of the 
protocol, and it is assumed that both ends will agree that such a function 
exists.

an IDL-based system need not necessarily pass a signature, as both the 
client and server would be assumed to know the signature of all 
functions/methods (and thus only need to send the raw data). however, this 
is more brittle, since it makes the limiting assumption that both parties 
use the exact same IDL (whereas, the use of names and signatures gives a 
little more room to expand, and a little more grace WRT error handling).


also possible is to forsake using static types for interfaces, and instead 
use a dynamically-typed system.
this can make things simpler and more generic, but could impact performance 
and does not itself address the issue of how to get arguments to/from 
statically-typed functions.

or such...



> 


0
Reply BGB 1/29/2010 1:02:03 AM

2 Replies
150 Views

(page loaded in 0.034 seconds)

Similiar Articles:













7/10/2012 8:04:53 PM


Reply: