Remote message-passing example

Hi,

I am looking for an example which shows how I can send a message from a
client thread on a local machine to a server thread on a remote machine
over QNET.

After reading the QNX documentation I’ve learned the following:

  • The Server has to use ChannelCreate(), MsgReceive() and MsgReply()
  • The Client has to use ConnectAttach() and MsgSend()

I’ve successfully managed to communicate two threads in the same node,
but I don’t know how to connecte remote nodes.

In ConnectAttach() I should specify the ND, the PID and the CHID. But,
since the communicating processes are remote how can I know the remote
PID and CHID?. As far as I know both parameters are specified at
run-time and I do not have a shared memory between them!!!.

So, an example could help.

Thank you,

Ramon

Ramon Sarrate <sarrate@esaii.upc.es> wrote:

Hi,

I am looking for an example which shows how I can send a message from a
client thread on a local machine to a server thread on a remote machine
over QNET.

open ("/net/magenta/dev/ser1", O_RDONLY);

After reading the QNX documentation I’ve learned the following:

  • The Server has to use ChannelCreate(), MsgReceive() and MsgReply()
  • The Client has to use ConnectAttach() and MsgSend()

I’ve successfully managed to communicate two threads in the same node,
but I don’t know how to connecte remote nodes.

It’s much easier to use “open()” instead of ConnectAttach(); the file
descriptor you get is a connection ID :slight_smile:

In ConnectAttach() I should specify the ND, the PID and the CHID. But,
since the communicating processes are remote how can I know the remote
PID and CHID?. As far as I know both parameters are specified at
run-time and I do not have a shared memory between them!!!.

So, an example could help.

Thank you,

Ramon


Robert Krten, PARSE Software Devices +1 613 599 8316.
Realtime Systems Architecture, Books, Video-based and Instructor-led
Training and Consulting at www.parse.com.
Email my initials at parse dot com.

Ramon Sarrate <sarrate@esaii.upc.es> wrote:

Hi,

I’ve successfully managed to communicate two threads in the same node,
but I don’t know how to connecte remote nodes.

In ConnectAttach() I should specify the ND, the PID and the CHID. But,
since the communicating processes are remote how can I know the remote
PID and CHID?. As far as I know both parameters are specified at
run-time and I do not have a shared memory between them!!!.

Now, how do you ConnectAttach() in local case? How do you get
those “local pid, chid” ?

Well, you memtioned “shared memory”, so I guess you are write that
into a shared memory area, right ? But if you can write to shared
memory, you can also write it into a file say /var/run/serverchannel,
and let the client open and read it out. The same “remote” case,
is to open /net/remote/var/run/serverchannel, and ConnectAttach() to
it.

But yes, you realize this break the whole purpose of IPC. That is,
2 process have to rely on 3rd party (be it the manager of shared memory,
or the manager of /var/run/serverchannel).

The solution of this is use “name space”, that is, the server would
associated it’s nd/pid/chid with a “name”. Thus, a client simply ask
to connect to, say, “/dev/myserver”, and got the connection. The name_*()
functions servers that purpose.

More further, you server may want to suppose those POSIX operation,
open/read/write/close/… Instead of attach a name, look each message
the client send to you and figure out what he want, you server could
use “resource manager” library, which, all these “standard message”
will be covered, and you only prepare functions like “open_handler()”,
“read_handler()”, “write_handler()” …

And that is the final solution for remote case.
open("/net/remote/dev/myserver", O_RDONLY), the client will got a fd
to read/write to, and the server, will have it’s “open_handler()”
get called. Both side do not need any special code to handle
“network case”.

-xtang

Thanks Xiaodan,

As you mention fisrt option (file-based) is no satisfactory.

Second option would be nice (but QNX docs say named_* functions are not
recommended for QNX 6 version)

Third option sounds me complex.

I would really like to illustrate to students how easily they can communicate
to remote threads via message-passing.

I have attached the sample code that I’ve written to check message-passing
communication between two threads of the same process. I would like to
transform this into two applications, one run on a local node and the other
in a remote node. So I would like to check message-passing communication
between two threads on remote nodes.

It would be nice if I you or someone else could provide this code.

thanks in advance,

Ramon



Xiaodan Tang wrote:

Ramon Sarrate <> sarrate@esaii.upc.es> > wrote:
Hi,

I’ve successfully managed to communicate two threads in the same node,
but I don’t know how to connecte remote nodes.

In ConnectAttach() I should specify the ND, the PID and the CHID. But,
since the communicating processes are remote how can I know the remote
PID and CHID?. As far as I know both parameters are specified at
run-time and I do not have a shared memory between them!!!.

Now, how do you ConnectAttach() in local case? How do you get
those “local pid, chid” ?

Well, you memtioned “shared memory”, so I guess you are write that
into a shared memory area, right ? But if you can write to shared
memory, you can also write it into a file say /var/run/serverchannel,
and let the client open and read it out. The same “remote” case,
is to open /net/remote/var/run/serverchannel, and ConnectAttach() to
it.

But yes, you realize this break the whole purpose of IPC. That is,
2 process have to rely on 3rd party (be it the manager of shared memory,
or the manager of /var/run/serverchannel).

The solution of this is use “name space”, that is, the server would
associated it’s nd/pid/chid with a “name”. Thus, a client simply ask
to connect to, say, “/dev/myserver”, and got the connection. The name_*()
functions servers that purpose.

More further, you server may want to suppose those POSIX operation,
open/read/write/close/… Instead of attach a name, look each message
the client send to you and figure out what he want, you server could
use “resource manager” library, which, all these “standard message”
will be covered, and you only prepare functions like “open_handler()”,
“read_handler()”, “write_handler()” …

And that is the final solution for remote case.
open("/net/remote/dev/myserver", O_RDONLY), the client will got a fd
to read/write to, and the server, will have it’s “open_handler()”
get called. Both side do not need any special code to handle
“network case”.

-xtang

hi,

will be NAME_FLAG_ATTACH_GLOBAL supported for name_* functions ?
it’s unsupported for a long time now ^^

stepan


“Xiaodan Tang” <xtang@qnx.com> pí¹e v diskusním pøíspìvku
news:ack0is$7o3$1@nntp.qnx.com

Ramon Sarrate <> sarrate@esaii.upc.es> > wrote:
Hi,

I’ve successfully managed to communicate two threads in the same node,
but I don’t know how to connecte remote nodes.

In ConnectAttach() I should specify the ND, the PID and the CHID. But,
since the communicating processes are remote how can I know the remote
PID and CHID?. As far as I know both parameters are specified at
run-time and I do not have a shared memory between them!!!.

Now, how do you ConnectAttach() in local case? How do you get
those “local pid, chid” ?

Well, you memtioned “shared memory”, so I guess you are write that
into a shared memory area, right ? But if you can write to shared
memory, you can also write it into a file say /var/run/serverchannel,
and let the client open and read it out. The same “remote” case,
is to open /net/remote/var/run/serverchannel, and ConnectAttach() to
it.

But yes, you realize this break the whole purpose of IPC. That is,
2 process have to rely on 3rd party (be it the manager of shared memory,
or the manager of /var/run/serverchannel).

The solution of this is use “name space”, that is, the server would
associated it’s nd/pid/chid with a “name”. Thus, a client simply ask
to connect to, say, “/dev/myserver”, and got the connection. The name_*()
functions servers that purpose.

More further, you server may want to suppose those POSIX operation,
open/read/write/close/… Instead of attach a name, look each message
the client send to you and figure out what he want, you server could
use “resource manager” library, which, all these “standard message”
will be covered, and you only prepare functions like “open_handler()”,
“read_handler()”, “write_handler()” …

And that is the final solution for remote case.
open("/net/remote/dev/myserver", O_RDONLY), the client will got a fd
to read/write to, and the server, will have it’s “open_handler()”
get called. Both side do not need any special code to handle
“network case”.

-xtang

Stepan Hejny <Stepan.Hejny@aveco.com> wrote:

hi,

will be NAME_FLAG_ATTACH_GLOBAL supported for name_* functions ?
it’s unsupported for a long time now ^^

It is supported in name_attach(), but is not supported in
name_open() function.

I am reposting my “gname_open()” function below, it works arround
the problem and give you connection to a GLOBAL attached name.

-xtang

----------------------- cut here --------------------------------
#include <sys/dispatch.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <share.h>

int gname_open(const char *name, int flags)
{
int fd;
DIR *dir;
struct dirent *dent;
char *newname;

if ((fd = name_open(name, flags)) != -1 || (flags & NAME_FLAG_ATTACH_GLOBAL) == 0) {
return fd;
}

if ((dir = opendir("/net")) == NULL) {
errno = ENOENT;
return -1;
}

while (dent = readdir(dir)) {
newname = alloca(strlen("/net/") + strlen(dent->d_name) +
strlen("/dev/name/global/") + strlen(name) + 1);
if (!newname) {
errno = ENOMEM;
return -1;
}
sprintf(newname, “/net/%s/dev/name/global/%s”, dent->d_name, name);
fd = _connect(_NTO_SIDE_CHANNEL, newname, 0, O_RDWR, SH_DENYNO,
_IO_CONNECT_OPEN, 1, _IO_FLAG_RD | _IO_FLAG_WR,
_FTYPE_NAME, 0, 0, 0, 0, 0, 0);
if (fd != -1) {
closedir(dir);
return fd;
}
}

closedir(dir);
errno = ENOENT;
return -1;
}

thank you


“Xiaodan Tang” <xtang@qnx.com> pí¹e v diskusním pøíspìvku
news:actjhq$9ak$4@nntp.qnx.com

Stepan Hejny <> Stepan.Hejny@aveco.com> > wrote:
hi,

will be NAME_FLAG_ATTACH_GLOBAL supported for name_* functions ?
it’s unsupported for a long time now ^^

It is supported in name_attach(), but is not supported in
name_open() function.

I am reposting my “gname_open()” function below, it works arround
the problem and give you connection to a GLOBAL attached name.

-xtang

----------------------- cut here --------------------------------
#include <sys/dispatch.h
#include <dirent.h
#include <errno.h
#include <fcntl.h
#include <share.h

int gname_open(const char *name, int flags)
{
int fd;
DIR *dir;
struct dirent *dent;
char *newname;

if ((fd = name_open(name, flags)) != -1 || (flags &
NAME_FLAG_ATTACH_GLOBAL) == 0) {
return fd;
}

if ((dir = opendir("/net")) == NULL) {
errno = ENOENT;
return -1;
}

while (dent = readdir(dir)) {
newname = alloca(strlen("/net/") + strlen(dent->d_name) +
strlen("/dev/name/global/") + strlen(name) + 1);
if (!newname) {
errno = ENOMEM;
return -1;
}
sprintf(newname, “/net/%s/dev/name/global/%s”, dent->d_name,
name);
fd = _connect(_NTO_SIDE_CHANNEL, newname, 0, O_RDWR, SH_DENYNO,
_IO_CONNECT_OPEN, 1, _IO_FLAG_RD | _IO_FLAG_WR,
_FTYPE_NAME, 0, 0, 0, 0, 0, 0);
if (fd != -1) {
closedir(dir);
return fd;
}
}

closedir(dir);
errno = ENOENT;
return -1;
}