LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-09-2011, 07:00 AM   #1
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Rep: Reputation: 32
Help about inter process communication,How to comunicate a struct between two process


Hello,

I need your help to understand IPC. We would like to send a struct with all values from process A to process B. There are a lot of ways to do it, shared memory, sockets, etc etc, but when I read a example or documents I dont understand how to do it.
I can do it with shared memory, but I am interesting in use socket, and I dont known how to do it.

Could you help me, or tell me where can I find a good example??

Best regards.
John Martin.

Last edited by webquinty; 05-09-2011 at 07:06 AM.
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 05-09-2011, 07:29 AM   #2
neonsignal
Senior Member
 
Registered: Jan 2005
Location: Melbourne, Australia
Distribution: Debian Bookworm (Fluxbox WM)
Posts: 1,391
Blog Entries: 54

Rep: Reputation: 360Reputation: 360Reputation: 360Reputation: 360
Since a socket is a byte oriented communication method, the usual method of sending a structure is to byte-serialize it. This means converting each of the structure members into a sequence of bytes and sending it to the receiving process in a well-defined order.

The best way to do this will depend on which language you are using. There are libraries that you may find helpful (such as the boost serialization library for C++, or s11n/c11n).

The naive approach is to cast a structure pointer as a byte pointer, you probably realize that this is quite non-portable (and portability is usually important when it comes to socket communication).
 
Old 05-09-2011, 08:30 AM   #3
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Original Poster
Rep: Reputation: 32
Thank you very much neonsignal.

I want to make a complex App, PROCESS A (real time C (pthreads)) and PROCESS B (Graphical interface using Qt). Real time process will be send data to HMI Qt app every 500 ms more or less. My idea is to use a socket to send data to HMI Qt, and show it.

Best regards.
 
Old 05-09-2011, 09:13 AM   #4
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by webquinty View Post
Thank you very much neonsignal.

I want to make a complex App, PROCESS A (real time C (pthreads)) and PROCESS B (Graphical interface using Qt). Real time process will be send data to HMI Qt app every 500 ms more or less. My idea is to use a socket to send data to HMI Qt, and show it.

Best regards.
If it guaranteed that both processes run in the same machine, you don't care about portability. I.e. you can send/receive your struct a block of bytes, the number of bytes in the block being 'sizeof(your_struct)'.

And if it is a UNIXish system, you can live without a socket, but use shared memory. Though socket is more portable across platforms.
 
Old 05-09-2011, 09:24 AM   #5
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Original Poster
Rep: Reputation: 32
Quote:
Originally Posted by Sergei Steshenko View Post
If it guaranteed that both processes run in the same machine, you don't care about portability. I.e. you can send/receive your struct a block of bytes, the number of bytes in the block being 'sizeof(your_struct)'.

And if it is a UNIXish system, you can live without a socket, but use shared memory. Though socket is more portable across platforms.
Hello,

Both process run in the same machine, then it is not very important portability.
I made some test with shared memory, but I am interesting in use socket, to compare what is the best option, socket or shared memory.

More or less, with shared memory is necessary to create in both process equal structs to shared data. With socket, I dont known what I need because I dont have any experience.

Best regards.
John Martin.
 
Old 05-09-2011, 09:36 AM   #6
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by webquinty View Post

...with shared memory is necessary to create in both process equal structs to shared data. ...
I am not sure I understand what you are saying - with shared memory just one struct is sufficient, and each process can have a pointer to that struct. What I also like is that shared memory data can be mapped onto a file, so it's easy to see the data during debugging - just contents of the file.
 
Old 05-09-2011, 10:21 AM   #7
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Original Poster
Rep: Reputation: 32
Quote:
Originally Posted by Sergei Steshenko View Post
I am not sure I understand what you are saying - with shared memory just one struct is sufficient, and each process can have a pointer to that struct. What I also like is that shared memory data can be mapped onto a file, so it's easy to see the data during debugging - just contents of the file.
Hello,

Perhaps I dont explain well. You are right, there is just one place where data is store (SHM), and both process access to this area. Internally, I declare a struct in both process to handle data more easy.

Best regards.
John Martin
 
Old 05-09-2011, 02:16 PM   #8
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by webquinty View Post
Real time [C (pthread)] process will be send data to HMI Qt app every 500 ms more or less. My idea is to use a socket to send data to HMI Qt, and show it.
It should be easy. First, open the socket (or named pipe) for writing at the sender end, and for reading at the receiver end. Then, use write() or send() to send data, and read() or recv() to receive it.

If you use only known size data types (double, unsigned char, char, uint16_t, int16_t, uint32_t, int32_t, uint64_t and int64_t), you can simply decide the data is in little-endian order (for example, on x86). If compiled to run on a non-little-endian architecture, add a function to convert the data between native byte order and little endian.

If you use more than one structure, you can first send a fixed-size ID and byte length, so the reader knows what to expect, and can even ignore the structure if it does not know its internal structure. For example JPEG (JFIF) files use this format with 32-bit ID and 32-bit length, but it works equally well for data streams.

You could also use an up to 22-byte byte-order-mark in files, to define the native byte order for all primitive data types (double, int64_t, int32_t, and int16_t) on the writer. There are only four permutations actually used, so the reader can compensate if necessary. Note that on some architectures floating-point types have different byte order than integers. I've done this for some physics simulations, because converting massive amounts of numerical data to/from text was too slow; it was important to let the writer use native byte order, but also allow any reader to correctly parse the data. It worked fine between all architectures I got my paws on (x86, SPARC, and POWER).

If you use a named pipe, both the reader and the writer can use normal file I/O, as long as the reader opens the pipe read-only, and the writer write-only. The open may block until there is an another end, so you should probably set a timeout via for example alarm() (with an empty SIGALRM signal handler function set via sigaction() to make the open interrupt when alarm occurs).
 
Old 05-10-2011, 10:45 AM   #9
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Original Poster
Rep: Reputation: 32
Quote:
Originally Posted by Nominal Animal View Post
If you use more than one structure, you can first send a fixed-size ID and byte length, so the reader knows what to expect, and can even ignore the structure if it does not know its internal structure. For example JPEG (JFIF) files use this format with 32-bit ID and 32-bit length, but it works equally well for data streams.
Hello Nominal Animal,

Could you explain me what is "fixed-size ID"?
is it like a identifier??

I have a lot of structs and vars to send from RealTime to Qt app, so I am not sure how to do it. I have not experience to use sockets.

Best regards
John Martin.

Last edited by webquinty; 05-10-2011 at 10:51 AM.
 
Old 05-10-2011, 08:12 PM   #10
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by webquinty View Post
Hello Nominal Animal,

Could you explain me what is "fixed-size ID"?
is it like a identifier??
Yes, exactly. In the simplest case, you prepend those to each of your data structures:
Code:
/* Explicitly define each type, so that omissions
 * and changes are forwards and backwards compatible.
*/
enum data_type {
    UNKNOWN = 0,
    FOO = 1,
    BAR = 2,
    BAZ = 3,
    /* ... */
};

struct data_foo {
    uint32_t     id;    /* = FOO */
    uint32_t     size;  /* = sizeof(struct data_foo) */
    /* .. foo payload follows .. */
};

struct data_bar {
    uint32_t     id;    /* = BAR */
    uint32_t     size;  /* = sizeof(struct data_bar) */
    /* .. bar payload follows .. */
};

struct data_baz {
    uint32_t     id;    /* = BAZ */
    uint32_t     size;  /* = sizeof(struct data_baz) */
    /* .. baz payload follows .. */
};

struct data_unknown {
    uint32_t     id;
    uint32_t     size;
    /* Payload structure is unknown, and therefore undefined. */
};
The realtime process can then simply write() or URL=http://www.kernel.org/doc/man-pages/online/pages/man2/send.2.html]send()[/URL] the structures -- both work fine --, just as if it was writing them into a file (but using unistd.h functions instead of stdio.h).

The reader process will URL=http://www.kernel.org/doc/man-pages/online/pages/man2/read.2.html]read()[/URL] at least eight bytes, preferably much more, and determine the size of the structure; then it can read the rest of the payload. After it has at least one complete structure, it can start inspecting the contents.

Note that the reader must keep reading the data, even if it cannot inspect everything, so that the realtime writer can keep writing to the pipe.

In the realtime writer, it is a good idea to set the socket to nonblocking. That way write() will return an error instead of blocking if the reader is too slow.

Quote:
Originally Posted by webquinty View Post
I have a lot of structs and vars to send from RealTime to Qt app, so I am not sure how to do it. I have not experience to use sockets.
There are UDP sockets, TCP sockets, unix domain sockets, and a few variants of pipes, in addition to shared memory. TCP and unix domain sockets and all pipes are sequential; the writer must write all data and reader must read all data in the same order. Shared memory is random-access, so it's easier to skip or miss a change. UDP sockets are small datagrams, typically less than 1500 bytes, but the limit depends on the network. Unix domain sockets and all pipes are local, but TCP and UDP work over the net, too.

Which one would you like to try? I'd personally go for TCP sockets, because sooner or later you'll want to dedicate the realtime machine to just realtime work, and gather the data on a remote workstation. Note that using TCP sockets does not mean you need a working net connection; the loopback interface (127.x.x.x) is (or should be) always available.

With TCP you have a reliable connection, and you can notify the reader about buffer overruns and about restarting data sends via ancillary data (basically a side band).

If you know you're only ever going to be local, shared memory is a clear winner. For very large memory structures you can use mmap() and msync(); see here for an example program I wrote that creates and handles a terabyte object in memory using a file-backed memory map.
 
2 members found this post helpful.
Old 05-11-2011, 03:52 AM   #11
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Original Poster
Rep: Reputation: 32
Hello Nominal Animal,

it is wonderful. Now I have not any doubts about it.

Thanks a lot.
John Martin.
 
Old 05-11-2011, 07:40 AM   #12
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by Nominal Animal View Post
Yes, exactly. In the simplest case, you prepend those to each of your data structures:
Code:
/* Explicitly define each type, so that omissions
 * and changes are forwards and backwards compatible.
*/
enum data_type {
    UNKNOWN = 0,
    FOO = 1,
    BAR = 2,
    BAZ = 3,
    /* ... */
};

struct data_foo {
    uint32_t     id;    /* = FOO */
    uint32_t     size;  /* = sizeof(struct data_foo) */
    /* .. foo payload follows .. */
};

struct data_bar {
    uint32_t     id;    /* = BAR */
    uint32_t     size;  /* = sizeof(struct data_bar) */
    /* .. bar payload follows .. */
};

struct data_baz {
    uint32_t     id;    /* = BAZ */
    uint32_t     size;  /* = sizeof(struct data_baz) */
    /* .. baz payload follows .. */
};

struct data_unknown {
    uint32_t     id;
    uint32_t     size;
    /* Payload structure is unknown, and therefore undefined. */
};
The realtime process can then simply write() or URL=http://www.kernel.org/doc/man-pages/online/pages/man2/send.2.html]send()[/URL] the structures -- both work fine --, just as if it was writing them into a file (but using unistd.h functions instead of stdio.h).

The reader process will URL=http://www.kernel.org/doc/man-pages/online/pages/man2/read.2.html]read()[/URL] at least eight bytes, preferably much more, and determine the size of the structure; then it can read the rest of the payload. After it has at least one complete structure, it can start inspecting the contents.

Note that the reader must keep reading the data, even if it cannot inspect everything, so that the realtime writer can keep writing to the pipe.

In the realtime writer, it is a good idea to set the socket to nonblocking. That way write() will return an error instead of blocking if the reader is too slow.



There are UDP sockets, TCP sockets, unix domain sockets, and a few variants of pipes, in addition to shared memory. TCP and unix domain sockets and all pipes are sequential; the writer must write all data and reader must read all data in the same order. Shared memory is random-access, so it's easier to skip or miss a change. UDP sockets are small datagrams, typically less than 1500 bytes, but the limit depends on the network. Unix domain sockets and all pipes are local, but TCP and UDP work over the net, too.

Which one would you like to try? I'd personally go for TCP sockets, because sooner or later you'll want to dedicate the realtime machine to just realtime work, and gather the data on a remote workstation. Note that using TCP sockets does not mean you need a working net connection; the loopback interface (127.x.x.x) is (or should be) always available.

With TCP you have a reliable connection, and you can notify the reader about buffer overruns and about restarting data sends via ancillary data (basically a side band).

If you know you're only ever going to be local, shared memory is a clear winner. For very large memory structures you can use mmap() and msync(); see here for an example program I wrote that creates and handles a terabyte object in memory using a file-backed memory map.
And why not use "C" union covering all legal for the case data types ?
 
Old 05-11-2011, 09:26 AM   #13
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by Sergei Steshenko View Post
And why not use "C" union covering all legal for the case data types ?
Heh heh, I omitted that to make the example simpler.

Actually, Sergei is quite right: using a union is the preferred method. Type punning the pointer to the structure works on all architectures, and so does putting the two fixed fields first in the structure, although on some architectures and compilers you might have to add a __attribute__ ((packed)) attribute to make sure the compiler does not pad the structure layout. Type punning the pointer is not the recommended way, however; using a union is.

(Also, you probably want to use #define's for the data type constants, to avoid having to recast the enum data_type to uint32_t.)

The union method uses an outer container structure, with the alternative structures in an union, sharing the same memory area but with different layouts:

Code:
#define DATA_UNKNOWN  0
#define DATA_FOO      1
#define DATA_BAR      2
#define DATA_BAZ      3

struct payload_foo {
    /* ... the foo payload ... */
};

struct payload_bar {
    /* ... the bar payload ... */
};

struct payload_baz {
    /* ... the baz payload ... */
};

/* Common data header */
struct data_header {
    uint32_t   type;
    uint32_t   size;
};

/* The container data structure: */
struct data {
    struct data_header  header;
    union {
        struct foo        foo;
        struct bar        bar;
        struct baz        baz;
    }                   payload;
};
The reason the data header is in a separate structure is that it allows you to allocate memory optimally for a specific data structure:
Code:
#include <stdlib.h>
#include <errno.h>

struct data *new_data(uint32_t const type)
{
    struct data *ptr;
    uint32_t     size;

    switch (payload_type) {
    case TYPE_FOO: size = sizeof(struct foo); break;
    case TYPE_BAR: size = sizeof(struct bar); break;
    case TYPE_BAZ: size = sizeof(struct baz); break;
    default:
        /* Unknown data type; fail. */
        errno = ENOENT;
        return NULL;
    };

    ptr = malloc(sizeof(struct data_header) + (size_t)size);
    if (!ptr) {
        /* Some malloc()s do not set errno at failure. */
        errno = ENOMEM;
        return NULL;
    }

    /* Note: This implementation sets size to the payload size.
     *       The other possibility is to include the header size too.
    */
    ptr->header.type = type;
    ptr->header.size = size;

    return ptr;
}
Note that the C99 standard says that if you use one member of the union to set the data (for example, ptr->payload.foo.something), you cannot use another member to read it. (It will work correctly on all compilers I've tested, but that's what the standard says.)

Sending a data structure is then for example
Code:
/** write_data() - Write the data to a socket or a file.
 * @descriptor     Socket or file descriptor
 * @ptr            Pointer to the struct data structure
 * If the write is successful, zero is returned.
 * Otherwise a nonzero error code (see errno) is returned.
*/
int write_data(int const descriptor, struct data const *const ptr)
{
    if (descriptor == -1 || !ptr)
        return EINVAL; /* Invalid parameters */

    {
        char const       *p = (char const *)ptr;
        char const *const q = p + ptr->header->size + sizeof(struct data_header);
        ssize_t           n;

        while (p < q) {
            n = write(descriptor, p, (size_t)(q - p));

            if (n > (ssize_t)0)
                p += (size_t)n;

            else
            if (n != (ssize_t)-1)
                return EIO; /* A library bug; this should never happen. */

            else
            if (errno == EINTR)
                continue; /* A signal was delivered, interrupting the write. */

            else
            if (errno == EWOULDBLOCK || errno == EAGAIN)
                continue; /* Socket is nonblocking, but the other end blocks. */

            else
                return errno; /* Any error condition. */
        }
    }

    return 0;
}
In the OP's case, it might be much simpler to separate the header altogether from the data types; the prototypes would then be for example
Code:
int write_data(int const descriptor,
               uint32_t const type,
               uint32_t const size,
               void const *const data);

int read_data(int const descriptor,
              uint32_t *const typeptr,
              uint32_t *const sizeptr,
              void **const dataptr);
where the read case works much like getline(), i.e. reallocates *dataptr if *sizeptr is not large enough.
(Note that realloc(NULL, size) is equivalent to malloc(size).)
 
Old 05-13-2011, 05:23 AM   #14
webquinty
Member
 
Registered: Apr 2008
Location: Espaņa
Distribution: Suse
Posts: 227

Original Poster
Rep: Reputation: 32
Hello,

Perhaps, could be another solution. RPC??

As I understand, RPC works like client - server procedure.
Server stanby until client make a connection, request some data and close conection.

But I don't known if it is more difficult than other solutions.

Best regards.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Errors in setting up inter-process comm. for KDE. tommy12 SUSE / openSUSE 0 08-24-2006 04:50 PM
inter process communication aral Programming 5 08-03-2006 01:37 PM
Monitor inter process communication across ports chtaylo3 Programming 0 07-12-2006 03:28 PM
how to do one to many inter process communication? Thinking Programming 2 12-14-2005 03:54 AM
KDE: Inter-process authentication problems elempoimen Linux - Software 1 06-10-2005 10:48 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:40 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration