views:

412

answers:

2

Hokay so I have an application where I need some IPC... I'm thinking named pipes are the way to go because they are so easy to use.

Anyways, I have a question about how to handle dynamic memory using named pipes.

Say I have a class such as this:

class MyTestClass {
public:
    MyTestClass() { _data = new int(4); }

    int GetData() { return *_data; }
    int GetData2() { return _data2; }

private:
    int* _data;
    int _data2;
};

Now when I create a buffer full of MyTestClass objects then send them over the pipe, I'm obviously losing _data in the destination process and getting garbage. Is there some strategy to this that I should use? I can use value types for simple cases, but for many complex classes I need to use some sort of dynamic memory and I like pointers.

Or, should I just look at using shared memory instead? Thanks

+3  A: 

Both named pipes and shared memory have similar issues: You need to serialize the contents of the structure into the on the sending side and deserialize the structure from the on the receiving side.

The serialization process is essentially identical whether you're using named pipes or shared memory. For embedded pointers (like _data and _data2) you need to serialize the contents of the pointer in a consistent fashion.

There are lots of serialization strategies that you could use, depending on how your structures are laid out in memory and how efficient your IPC has to be. Or you could use DCE RPC and let the RPC marshaling code handle the complexities for you.

Larry Osterman
Thanks for the response... any tips on protocols I could use or serialization strategies I could use? Thanks
Polaris878
If you're looking for serialization strategies, by far the most common case is file storage. How would you write your class to a file and read it back later? You might be able to save yourself a lot of work if you wrap your IPC channel as a `std::streambuf`; that way you can share and reuse a lot of code.
MSalters
MSalters took the words right out of my mouth. His suggestion is spot on.
Larry Osterman
+1  A: 

To send the data over a named pipe, you must serialize (or marshal) the data on the sending end, and deserialize (or unmarshal) it on the receiving end.

It sounds suspiciously as if you are simply writing a copy of the bytes in the data structure. This is no good whatsoever. You aren't copying the allocated data (it isn't stored between the first and last bytes of the data structure, but somewhere else altogether) and you are copying a pointer (_data) from one machine (or process) to another, and the memory address in the local process has no guaranteed meaning in the other.

Define yourself a wire protocol (if desparate, look at ASN.1 - no, on second thoughts, don't get that desparate) that defines the layout of the data for transmission over the wire. Then implement sender and receiver (or seralizer and deserializer) functions. Or find someone else's code that does this already.

Also remember to deal with endian-ness - you must define which sequence the bytes are sent through the named pipe.

For example, you could define that the message sent consists of a 4-byte unsigned integer in network byte order defining how many structures follow, and each structure could be a sequence of 4 signed 4-byte integers for the array followed by a single signed 4-byte integer for _data2 (also sent in network byte order).

Note that the choice of named pipe as the IPC mechanism is largely immaterial; unless you are using shared memory (inherently on the same machine), then endian-ness has to be dealt with, and even with shared memory, you need to deal with serialization.

Jonathan Leffler
Thanks... Thats what I was thinking... I'm a bit new to IPC stuff. Right now I was just sending raw bytes through haha... I wanted to see what the limits of these IPC mechanisms were. You are 100% right about the bytes not being in the data structure... that's exactly the problem I was trying to solve.
Polaris878