编程接口指南

第 9 章 传输选择和名称到地址的映射

本章介绍如何选择传输以及如何解析网络地址,并进一步介绍了可用于为应用程序指定可用通信协议的接口。另外,还介绍了用于提供名称到网络地址的直接映射的其他接口。


注 –

在本章中,术语网络传输可互换使用。这两个术语指的是符合 OSI 参考模型的传输层的程序接口。术语网络还用于指代通过某种电子介质连接的多台计算机的物理集合。


传输选择


注意 – 注意 –

本章中介绍的接口具有多线程安全性。“多线程安全”表示可以在多线程应用程序中随意使用包含传输选择接口调用的应用程序。这些接口调用不提供线性可伸缩性,因为它们不可重复执行。


分布式应用程序必须使用标准的传输服务接口,以便可移植到其他协议。传输选择服务提供了一个接口,应用程序可通过此接口选择要使用的协议。使用此接口,应用程序可独立于协议和介质。

传输选择表示客户机应用程序可轻松尝试每种可用传输,直到该客户机与服务器建立通信为止。利用传输选择,服务器应用程序可接受多个传输请求。应用程序随后可以通过多种协议进行通信。既可按照本地缺省序列指定的顺序尝试传输,也可按照用户指定的顺序尝试传输。

应用程序负责从可用传输中进行选择。传输选择机制可统一并简化选择。

名称到地址的映射

利用名称到地址的映射,应用程序可获取与所用传输无关的指定主机上服务的地址。名称到地址的映射由以下接口组成:

netdir_getbyname(3NSL)

将主机名和服务名映射到一个地址集

netdir_getbyaddr(3NSL)

将地址映射到主机名和服务名

netdir_free(3NSL)

释放由名称到地址的转换例程所分配的结构

taddr2uaddr(3NSL)

转换某个地址,并返回该地址与传输无关的字符表示形式。

uaddr2taddr(3NSL)

将通用地址转换为 netbuf 结构

netdir_options(3NSL)

特定于传输的功能(如 TCP 和 UDP 的广播地址和保留端口功能)的接口

netdir_perror(3NSL)

stderr 中显示一条消息,说明用来将名称映射到地址的例程之一失败的原因。

netdir_sperror(3NSL)

返回一个字符串,其中包含的错误消息说明了用来将名称映射到地址的例程之一失败的原因。

每个例程的第一个参数都指向用于说明传输的 netconfig(4) 结构。例程使用 netconfig(4) 结构中的目录查找库路径数组来调用每个路径,直到转换成功为止。

名称到地址的库在表 9–1 中介绍。使用名称到地址的映射例程中介绍的例程在 netdir(3NSL) 手册页中定义。


注 –

Solaris™ 环境中将不再存在以下库: tcpip.soswitch.sonis.so。有关此更改的更多信息,请参见 nsswitch.conf(4) 手册页和 gethostbyname(3NSL) 手册页的“注释”部分。


表 9–1 名称到地址的库

库 

传输系列 

说明 

-

inet

针对协议族 inet 的网络的名称到地址映射由名称服务转换器基于文件 nsswitch.conf(4) 中对应于 hostsservices 的项提供。对于其他系列的网络,短划线表示无法正常使用的名称到地址的映射。

straddr.so

loopback

包含在接受字符串作为地址的任何协议中执行名称到地址映射的例程,如回送传输。 

straddr.so

straddr.so 库的名称到地址转换文件由系统管理员创建。系统管理员还将维护这些转换文件。 straddr.so 文件包括 /etc/net/transport-name/hosts/etc/net/transport-name/servicestransport-name 是指接受字符串地址的传输的本地名称,在 /etc/netconfig 文件的 network ID 字段中指定。例如,ticlts 的主机文件可以是 /etc/net/ticlts/hoststiclts 的服务文件可以是 /etc/net/ticlts/services

大多数字符串地址不区分 hostservice。不过,将字符串分隔为主机部分和服务部分这一点与其他传输是一致的。/etc/net/transport-name/hosts 文件包含一个假定为主机地址的文本字符串,后跟主机名:

joyluckaddr

joyluck

carpediemaddr

carpediem

thehopaddr

thehop

pongoaddr

pongo

由于回送传输的范围不能超出包含主机,因此列出其他主机毫无意义。

/etc/net/transport-name/services 文件包含后跟标识服务地址的字符串的服务名:


rpcbind	rpc

listen	serve

例程可通过串联主机地址、句点 (.) 和服务地址来创建全字符串地址。例如,pongolisten 服务的地址为 pongoaddr.serve

应用程序请求某个传输上使用该库的特定主机中服务的地址时,/etc/net/transport/hosts 中必须包含主机名。/etc/net/transport/services 中必须包含服务名。如果缺少任一名称,则名称到地址的转换将失败。

使用名称到地址的映射例程

本节概述了可供使用的映射例程。这些例程会返回网络名称或将其转换为各自的网络地址。请注意,netdir_getbyname(3NSL)netdir_getbyaddr(3NSL)taddr2uaddr(3NSL) 可返回指向必须通过 netdir_free(3NSL) 调用来释放的数据的指针。

	int netdir_getbyname(struct netconfig *nconf, 

			struct nd_hostserv *service, struct nd_addrlist **addrs);

netdir_getbyname(3NSL) 可将 service 中指定的主机名和服务名映射到一组与 nconf 中标识的传输一致的地址。nd_hostservnd_addrlist 结构在 netdir(3NSL) 手册页中定义。addrs 中会返回一个指向上述地址的指针。

要查找所有可用传输上的主机和服务的所有地址,请使用 getnetpath(3NSL)getnetconfig(3NSL) 返回的每个 netconfig(4) 结构来调用 netdir_getbyname(3NSL)

int netdir_getbyaddr(struct netconfig *nconf,

		struct nd_hostservlist **service, struct netbuf *netaddr);

netdir_getbyaddr(3NSL) 可将地址映射到主机名和服务名。此接口使用 netaddr 中的地址进行调用,并会返回 service 中主机名和服务名对的列表。nd_hostservlist 结构在 netdir(3NSL) 中定义。

void netdir_free(void *ptr, int struct_type);

netdir_free(3NSL) 例程可释放由名称到地址的转换例程所分配的结构。参数可采用下表中显示的值。

表 9–2 netdir_free(3NSL) 例程

struct_type

ptr

ND_HOSTSERV

指向 nd_hostserv 结构的指针

ND_HOSTSERVLIST

指向 nd_hostservlist 结构的指针

ND_ADDR

指向 netbuf 结构的指针

ND_ADDRLIST

指向 nd_addrlist 结构的指针

char *taddr2uaddr(struct netconfig *nconf, struct netbuf *addr);

taddr2uaddr(3NSL) 可转换 addr 指向的地址,并返回该地址与传输无关的字符表示形式。此字符表示形式称为通用地址。nconf 中给定的值可指定该地址针对其有效的传输。通用地址可通过 free(3C) 进行释放。

struct netbuf *uaddr2taddr(struct netconfig *nconf, char *uaddr);

uaddr 指向的通用地址会转换为 netbuf 结构。nconf 可指定该地址针对其有效的传输。

int netdir_options(const struct netconfig *config,

 		 const int option, const int fildes, char *point_to_args);

netdir_options(3NSL) 提供了特定于传输的功能(如 TCP 和 UDP 的广播地址和保留端口功能)的接口。nconf 的值指定传输,而 option 则指定要执行的特定于传输的操作。option 中的值可能会导致忽略 fd 中的值。第四个参数指向特定于操作的数据。

下表说明了用于 option 的值。

表 9–3 netdir_options 的值

选项 

说明 

ND_SET_BROADCAST

在传输支持广播时设置广播的传输 

ND_SET_RESERVEDPORT

在传输允许的情况下使应用程序绑定到保留端口 

ND_CHECK_RESERVEDPORT

在传输支持保留端口的情况下验证地址是否对应于保留端口 

ND_MERGEADDR

将本地有意义的地址转换为客户机主机可连接到的地址 

netdir_perror(3NSL) 例程会在 stderr 中显示一条消息,说明用来将名称映射到地址的例程之一失败的原因。

void netdir_perror(char *s);

netdir_sperror(3NSL) 返回一个字符串,其中包含的错误消息说明了用来将名称映射到地址的例程之一失败的原因。

char *netdir_sperror(void);

以下示例说明了如何执行网络选择和名称到地址的映射。


示例 9–1 网络选择和名称到地址的映射

#include <netconfig.h>

#include <netdir.h>

#include <sys/tiuser.h>



struct nd_hostserv nd_hostserv;   /* host and service information */

struct nd_addrlist *nd_addrlistp; /* addresses for the service */

struct netbuf *netbufp;           /* the address of the service */

struct netconfig *nconf;          /* transport information*/

int i;                            /* the number of addresses */

char *uaddr;                      /* service universal address */

void *handlep;                    /* a handle into network selection */

/*

 * Set the host structure to reference the "date"

 * service on host "gandalf"

 */

nd_hostserv.h_host = "gandalf";

nd_hostserv.h_serv = "date";

/*

 * Initialize the network selection mechanism.

 */

if ((handlep = setnetpath()) == (void *)NULL) {

   nc_perror(argv[0]);

   exit(1);

}

/*

 * Loop through the transport providers.

 */

while ((nconf = getnetpath(handlep)) != (struct netconfig *)NULL)

{

   /*

    * Print out the information associated with the

    * transport provider described in the "netconfig"

    * structure.

    */

   printf("Transport provider name: %s\n", nconf->nc_netid);

   printf("Transport protocol family: %s\n", nconf->nc_protofmly);

   printf("The transport device file: %s\n", nconf->nc_device);

   printf("Transport provider semantics: ");

	   switch (nconf->nc_semantics) {

   case NC_TPI_COTS:

      printf("virtual circuit\n");

      break;

   case NC_TPI_COTS_ORD:

      printf("virtual circuit with orderly release\n");

      break;



   case NC_TPI_CLTS:

      printf("datagram\n");

      break;

   }

   /*

    * Get the address for service "date" on the host

    * named "gandalf" over the transport provider

    * specified in the netconfig structure.

    */

   if (netdir_getbyname(nconf, &nd_hostserv, &nd_addrlistp) != ND_OK) {

      printf("Cannot determine address for service\n");

      netdir_perror(argv[0]);

      continue;

   }

   printf("<%d> addresses of date service on gandalf:\n",

      nd_addrlistp->n_cnt);

   /*

    * Print out all addresses for service "date" on

    * host "gandalf" on current transport provider.

    */

   netbufp = nd_addrlistp->n_addrs;

   for (i = 0; i < nd_addrlistp->n_cnt; i++, netbufp++) {

      uaddr = taddr2uaddr(nconf,netbufp);

      printf("%s\n",uaddr);

      free(uaddr);

   }

   	netdir_free( nd_addrlistp, ND_ADDRLIST );



}

endnetconfig(handlep);