Client-server C program

Can anybody send me a simple programs (client and server) written under QNX 6.3 with usage of MsgSend() and MsgReceive()?

There is a quite good example for Server/Client within the docu under “name_attach()”
QNX NTO RTOS → Library Reference → N → name_attach()

Thanks :slight_smile:

There’s something I don’t understand…
I want 2 computers to communicate in a local network.
I suppose that i should create global name.
So I have
attach = name_attach(NULL, ATTACH_POINT,NAME_FLAG_ATTACH_GLOBAL)
and in /dev/name/global I have my name.
So it seems like server is running properly.

In clients part I have:
name_open(ATTACH_POINT, NAME_FLAG_ATTACH_GLOBAL)
and client is ending here… ( EXIT_FAILURE ).

Can anybody know why? What should I do to make it work?

With name_attach(“myName”, local) you will create a channel in /dev/name/local/myName - this is to your server.

name_open(“myName”,local) will open/connect to your server about the channel “myName”. name_open() will return a ID (like a filedescriptor, if -1 when fails) you use this value in MsgSend(). On your server you wait with MsgReceive().

Are you saying that creating local server is enough? Earlier i did
name_attach(NULL, ATTACH_POINT,0)
and I had myName in /dev/name/local
On client I had
name_open(ATTACH_POINT, 0)

and it did’t work.
name_open() didn’t find myName…

So for my purposes local name creating will be good?
Why my client-server don’t work?

Maybe problem is with gns? I checked and on server and on client it works as “client”. Maybe this is the reason why my programs can’t communicate?
If yes than what should I do to make that gns will work as server on my server-computer?

Ok, I misunderstand, your client and server will be run on two pc’s right ? Then it is “right” that they didn’t communicate, because the channel will only exist on the local machine.

What you need is the QNET functions like: ConnectAttacht() look in the IDE help for more informations about this functions

So this sample that is available in Library Reference (name_attach()) will only work on 1 computer (ment client and server on the same computer)?

I don’t know what you mean. Client run on one pc and the server on a second pc - right?!

For QNET look here in the IDE help:http://127.0.0.1:59062/help/topic/com.qnx.tools.ide.doc.pe/neutrino/sys_arch/qnet.html?resultof=%22%71%6e%65%74%22%20 (or search for: Native Networking).

Another way is to use TCP/IP sockets for communication. Do you want sent only short (!) messages or more …?

Link you gave doesn’t work.
I have to use QNet. I know TCP/IP but my assumptions was different.
My messages would be rather short. Max 100 characters.
And yes I want to have client on one computer, and server on another.
I thought that this example is well for my needs
qnx.com/developers/docs/6.3. … ttach.html
What should I add to this example and where to make it work as I want?

Ok, try this:

name_attach(NULL,“myGlobalName”,NAME_FLAG_ATTACH_GLOBAL) , so you attach the channel not local …

The link is from the IDE help - here is the Internet link http://partners.qnx.com/developers/docs/6.3.0SP3/neutrino/user_guide/qnet.html

As you can see before I did try global name and it didn’t work :frowning:

So I’m asking again: how to make this example from Library reference work on 2 computers? (client and server on different computers)

Ok, it’s not gns fault.
On my server I did: gns -s
and on client I did: gns -c
It didn’t help (

Can anybody help me?

Normally on a single PC you use name_open() to return a coid and all is golden. In QNX 4.25, the equivalent function code also take a node number and again you were fine. For better or worse, this doesn’t work in QNX 6.x

You have to switch from name_open() to ConnectAttach() to pass a node. The downside is that name_open() only needed a name, which you picked in advance and knew what it was. With ConnectAttach() you need the node, the process id (pid), and the channel id (chid). Getting the node is easy, assuming again you have a fixed node name known in advance. Call netmgr_strtond(“nodename”, NULL) and you get the nd to pass as the first argument to ConnectAttach(). But what about pid and chid? You could at least theoretically get the pid by looking at the processes running on the server machine, although there are lots of problems with that approach. But there’s absolutely NO WAY to get the chid. Chid is returned from the name_attach() call on the server side, and the OS doesn’t publish it.

You now have a chicken-and-egg problem. If you could attach to the server, you could request the pid and chid, but you need the pid and chid to attach to the server. THERE IS NO SOLUTION TO THIS PROBLEM WITHIN THE MESSAGE PASSING FRAMEWORK.

So how do you do it? You must step outside the message passing framework. There are numerous possibilities, but here are a few relatively practical ones:

  1. After the server does its name_attach() call, it can write the pid and chid to a file with a predetermined path and name. Then just read the file over QNET from the client.
  2. Use TCP/IP to get the pid and chid, then switch over to MsgSend/MsgReceive. This means that either the server must handle TCP/IP requests as well as QNX message passing, or a secondary server will be needed.
  3. Write a resource manager, which will act like file-level IO. This looks a lot like choice 1, but with a lot more code. This happens to be the route that I picked when faced with this dilemna. I’m not convinced I made the right choice.

Final note: the 4th parameter to ConnectAttach() is index; set it to _NTO_SIDE_CHANNEL. The final parameter, flags, will probably be 0. So your to ConnectAttach() is:

// somehow get the pid // somehow get the chid int nd = netmgr_strtond("node_name", NULL); // probably ought to error check nd here coid = ConnectAttach(nd, pid, chid, _NTO_SIDE_CHANNEL, 0); // really, really ought to error check coid
All that to replace coid = name_open(“server_name”, 0);

Hope that makes any kind of sense at all.

-James Ingraham
Sage Automation, Inc.

Thanks for your response. Only how to read the file that is on the server if I can’t connect to server? I’m interested in the easiest and fastest way :slight_smile:

And silly question… What is “nodename”? Is it the name attached on server by name_attach()?

Btw it seems very complicated… Are you sure it’s so difficult? QNX is well known for it’s communication and to be frank I’m quite suprised with these difficulties :frowning:

The code you posted should have worked localy and remotely. When you started gns -c did you provide the server name. Also if you read carefully the documentation you will notice that the server must support some QNX Messages in order to support gns.

When I started gns -c I provided server name, and next time I didn’t. Both ways it didn’t work.
What do you ment about supporting QNX Messages?

You need to start gns as a server on one node, and gns as a client on all other nodes, as I read it from the docs, ie

(on node1)
gns -s

(on node2)
gns -c node1

And I did it. On client I did
gns -c ser
(where ser was my ATTACH_POINT in name_attach(NULL, ATTACH_POINT, 0) on server)
It didn’t work :frowning:

can you post all of your code. I know for a fact this works.

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/dispatch.h>

#define ATTACH_POINT “ser”

/* We specify the header as being at least a pulse */
typedef struct _pulse msg_header_t;

/* Our real data comes after the header */
typedef struct _my_data {
msg_header_t hdr;
int data;
} my_data_t;

/*** Server Side of the code ***/
int server() {
name_attach_t *attach;
my_data_t msg;
int rcvid;

/* Create a global name (/dev/name/global/…) */
if ((attach = name_attach(NULL, ATTACH_POINT, NAME_FLAG_ATTACH_GLOBAL)) == NULL) {
return EXIT_FAILURE;
}

/* Do your MsgReceive’s here now with the chid */
while (1) {
rcvid = MsgReceive(attach->chid, &msg, sizeof(msg), NULL);

   if (rcvid == -1) {/* Error condition, exit */
       break;
   }

   if (rcvid == 0) {/* Pulse received */
       switch (msg.hdr.code) {
       case _PULSE_CODE_DISCONNECT:
           /*
            * A client disconnected all its connections (called
            * name_close() for each name_open() of our name) or
            * terminated
            */
           ConnectDetach(msg.hdr.scoid);
           break;
       case _PULSE_CODE_UNBLOCK:
           /*
            * REPLY blocked client wants to unblock (was hit by
            * a signal or timed out).  It's up to you if you
            * reply now or later.
            */
           break;
       default:
           /*
            * A pulse sent by one of your processes or a
            * _PULSE_CODE_COIDDEATH or _PULSE_CODE_THREADDEATH
            * from the kernel?
    */
       }
       continue;
   }

   /* name_open() sends a connect message, must EOK this */
   if (msg.hdr.type == _IO_CONNECT ) {
       MsgReply( rcvid, EOK, NULL, 0 );
       continue;
   }

   /* Some other QNX IO message was received; reject it */
   if (msg.hdr.type > _IO_BASE && msg.hdr.type <= _IO_MAX ) {
       MsgError( rcvid, ENOSYS );
       continue;
   }

   /* A message (presumable ours) received, handle */
   printf("Server receive %d \n", msg.data);
   MsgReply(rcvid, EOK, 0, 0);

}

/* Remove the name from the space */
name_detach(attach, 0);

return EXIT_SUCCESS;
}

/*** Client Side of the code ***/
int client() {
my_data_t msg;
int fd;

if ((fd = name_open(ATTACH_POINT, NAME_FLAG_ATTACH_GLOBAL)) == -1) {
    return EXIT_FAILURE;
}

/* We would have pre-defined data to stuff here */
msg.hdr.type = 0x00;
msg.hdr.subtype = 0x00;

/* Do whatever work you wanted with server connection */
for (msg.data=0; msg.data < 5; msg.data++) {
    printf("Client sending %d \n", msg.data);
    if (MsgSend(fd, &msg, sizeof(msg), NULL, 0) == -1) {
        break;
    }
}

/* Close the connection */
name_close(fd);
return EXIT_SUCCESS;

}

int main(int argc, char **argv) {
int ret;

if (argc < 2) {
    printf("Usage %s -s | -c \n", argv[0]);
    ret = EXIT_FAILURE;
}
else if (strcmp(argv[1], "-c") == 0) {
    printf("Running Client ... \n");
    ret = client();   /* see name_open() for this code */
}
else if (strcmp(argv[1], "-s") == 0) {
    printf("Running Server ... \n");
    ret = server();   /* see name_attach() for this code */
}
else {
    printf("Usage %s -s | -c \n", argv[0]);
    ret = EXIT_FAILURE;
}
return ret;

}

It’s an example from library reference. I’ve run it on server as server and on client (other computer) as a client…