QNX的GNS 部署
GNS 部署
GNS的几种模式
GNS实用程序以两种不同的模式运行:服务器模式和客户端模式。服务器模式管理器是存储通知服务并处理查找和连接请求的*数据库。客户端模式管理器在本地应用程序和GNS服务器之间传递通知、查找和连接请求。
以下是通过网络分布的GNS客户端和GNS服务器的简单布局例子:
Figure 1. 一个简单的GNS布局设置。
在本例中,设计了一个GNS客户端和一个GNS服务器。就应用程序而言,GNS服务是一个实体。客户机-服务器关系仅存在于GNS进程之间。服务器GNS进程跟踪全局注册的服务,而另一个节点上的客户端GNS进程将该节点的GNS请求转发给GNS服务器。
当客户端和服务器应用程序与GNS服务交互时,它们使用以下API:
服务端:
使用GNS服务器注册您的服务。
使用GNS服务器取消您的服务。
客户端:
通过GNS服务器打开服务。
关闭打开的服务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