QNX的GNS 部署

GNS 部署

GNS的几种模式

GNS实用程序以两种不同的模式运行:服务器模式和客户端模式。服务器模式管理器是存储通知服务并处理查找和连接请求的中央数据库。客户端模式管理器在本地应用程序和GNS服务器之间传递通知、查找和连接请求。

以下是通过网络分布的GNS客户端和GNS服务器的简单布局例子:


Figure 1. 一个简单的GNS布局设置。

在本例中,设计了一个GNS客户端和一个GNS服务器。就应用程序而言,GNS服务是一个实体。客户机-服务器关系仅存在于GNS进程之间。服务器GNS进程跟踪全局注册的服务,而另一个节点上的客户端GNS进程将该节点的GNS请求转发给GNS服务器。

       当客户端和服务器应用程序与GNS服务交互时,它们使用以下API:

服务端:

name_attach()

使用GNS服务器注册您的服务。

name_detach()

使用GNS服务器取消您的服务。

客户端:

name_open()

通过GNS服务器打开服务。

name_close()

关闭打开的服务name_open().

GNS注册服务

为了使用GNS,首先需要通过调用name_attach()GNS注册管理器进程。当注册一个服务,需要决定这个管理器的服务是在本地注册服务,还是在全局注册。如果在本地注册服务,只有本地节点能够看到该服务;另一个节点看不到它。这使可以让客户端应用程序查找服务名,而不是在其它执行的节点上查找路径名。本文档重点介绍了在全局注册。

当全局注册GNS服务时,运行客户端应用程序的网络上的任何节点都可以使用该服务,前提是该节点正在运行GNS客户端进程需要连接到GNS服务器,以及运行GNS服务器进程的节点上的客户端应用程序。您可以使用一个典型的name_attach()调用,如下所示:

if ((attach = name_attach(NULL, "printer", NAME_FLAG_ATTACH_GLOBAL)) == NULL) {
     return EXIT_FAILURE;
     }

设置传递标记为NAME_FLAG_ATTACH_GLOBAL。表示服务被全局注册,而不是本地注册。最后要注意的是名字。这是客户端搜索的名称。这个名称可以有一个级别,如上面所示,也可以嵌套,如打印机/ps。电话是这样的:

if ((attach = name_attach(NULL, "printer/ps", NAME_FLAG_ATTACH_GLOBAL)) == NULL) {
     return EXIT_FAILURE;
     }

嵌套名称对服务的工作方式没有影响。唯一的区别是在gns生成的文件系统中如何组织服务。例如

$ ls -l /dev/name/global/
total 2
dr-xr-xr-x  0 root      techies           1 Feb 06 16:20 net
dr-xr-xr-x  0 root      techies           1 Feb 06 16:21 printer
$ ls -l /dev/name/global/printer
total 1
dr-xr-xr-x  0 root      techies           1 Feb 06 16:21 ps

name_attach()函数的第一个参数是调度句柄。一旦创建了调度结构,就将调度句柄传递给name_attach()。如果此参数为空,则自动创建调度结构。

如果服务器应用程序的多个实例(或两个或多个注册相同服务名称的应用程序)被启动并在GNS中注册,会发生什么情况?这被视为冗余服务。如果一个应用程序终止或分离其服务,则另一个服务接管。但是,它不是循环配置;所有请求都转到一个应用程序,直到它不再可用。此时,请求解析到注册了相同服务的另一个应用程序。对于附加为本地服务的应用程序,没有凭证限制。只有当应用程序具有根特权时,应用程序才能全局地附加服务。当您的应用程序终止时,或者不希望通过GNS提供对服务的访问时,您应该调用name_detach()。这将从GNS中删除服务。

 if ((fd = name_open("printer", NAME_FLAG_ATTACH_GLOBAL)) == -1) {
     return EXIT_FAILURE;
     }
or: 
if ((fd = name_open("printer/ps", NAME_FLAG_ATTACH_GLOBAL)) == -1) {
     return EXIT_FAILURE;
     }

如果不指定此标志,GNS只查找本地服务。该函数返回一个fd,然后可以通过发送消息来访问服务管理器,就像它直接将服务打开为/dev/par1/net/node/dev/par1一样。

if ((fd = name_open("printer/ps", 0)) == -1) {
     return EXIT_FAILURE;
     }

API函数

name_open()

为服务器连接打开一个名称

Synopsis:

#include <sys/iofunc.h>

#include <sys/dispatch.h>

int name_open(const char * name, int flags );

Arguments:

name

要为服务器连接打开的名称。

flags

影响函数行为的标志:

·        NAME_FLAG_ATTACH_GLOBAL —   搜索全局名称而不是本地名称。

name_close()

关闭name_open()打开的服务器连接

Synopsis:

#include <sys/iofunc.h>

#include <sys/dispatch.h>

int name_close( int coid );

Arguments:

coid

A side-channel connection ID returned byname_open().

Description:

The name_close() function closes a server connection thatwas opened by name_open().

name_detach()

Remove a namefrom the namespace and destroy the channel

Synopsis:

#include <sys/iofunc.h>

#include <sys/dispatch.h>

 

int name_detach( name_attach_t * attach,

                 unsigned flags );

Arguments:

attach

A pointer to the name_attach_t structure returned by a successful call toname_attach().

flags

Flags that affect the function'sbehavior:

·        NAME_FLAG_DETACH_SAVEDPP — don't destroy the dispatch handle.

Library:

libc

Use the -l c option to qcc to link against this library. This libraryis usually included automatically.

Description:

name_detach()函数从名称空间中删除名称,name_attach()创建的通道。如果在标志中设置NAME_FLAG _DETACH_SAVEDPP,则name_attach_t结构中包含的分派指针不会被删除;可以通过调用dispatch _destroy()来销毁它,默认情况是销毁分派指针。

name_attach()

在名称空间中注册一个名称并创建一个通道。

Synopsis:

#include <sys/iofunc.h>

#include <sys/dispatch.h>

 

name_attach_t * name_attach( dispatch_t * dpp,

                             const char * path,

                             unsigned flags);

Arguments:

dpp

NULL, or a dispatch handle returned by a successful call to dispatch_create() or dispatch_create_channel().

path

The path that you want to register under/dev/name/[local|global]/. This name shouldn't contain any path components consisting of .. or start with a leading slash (/).

flags

Flags that affect the function'sbehavior:

·        NAME_FLAG_ATTACH_GLOBAL — attach the name globally instead of locally. See the gns utility.

GNS测试例子

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dispatch.h>
 
#define ATTACH_POINT "myname"
 
/* 将报头指定为脉冲信号*/
typedef struct _pulse msg_header_t;
/* 把数据负载附加在后面 */
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 local name (/dev/name/local/...) */
   if ((attach = name_attach(NULL, ATTACH_POINT, 0)) == 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: //当客服端口调用close时,会触发此脉冲,通知关闭链接
                      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?
                */
               break;
           }
           continue;
       }
 
       /* If the Global Name Service (gns) is running, name_open()
          sends a connect message. The server  must EOK it. */
       if (msg.hdr.type == _IO_CONNECT ) {
           MsgReply( rcvid, EOK, NULL, 0 );
           continue;
       }
 
       /* Some other I/O 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 server_coid;
 
    if ((server_coid = name_open(ATTACH_POINT, 0)) == -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(server_coid, &msg, sizeof(msg), NULL, 0) == -1) {
            break;
        }
    }
    /* Close the connection */
    name_close(server_coid);
    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;
}
 

测试输出结果

/dev/name/local目录下有一个myname

猜你喜欢

转载自blog.csdn.net/u011996698/article/details/80834334