トランスポート独立の RPC ルーチン (TI-RPC ルーチン) を使用すると、アプリケーション開発者はトランスポート層へのアクセスレベルを自由に選択できます。最上位レベルのルーチンは、トランスポートが完全に抽象化されて、本当の意味でトランスポート独立になっています。下位レベルのルーチンを使用すると、旧バージョンと同じように個々のトランスポートに依存したアクセスレベルになります。
この節では、トランスポート特定 RPC (TS-RPC) アプリケーションを TI-RPC へ移行するための非公式ガイドになっています。表 4-11 では、いくつかのルーチンを選んで相違点を示します。ソケットとトランスポート層インタフェース (TLI) の移行の問題点についての詳細は、『Transport Interfaces Programming Guide』を参照してください。
TCP または UDP に基づくアプリケーションはバイナリ互換モードで実行できます。すべてのソースファイルをコンパイルし直したり、リンクし直したりできるのは、一部のアプリケーションだけです。RPC 呼び出しだけを使用し、ソケット、TCP、UDP に固有の機能を使用していないアプリケーションがこれに当たります。
ソケットセマンティクスに依存していたり、TCP や UDP の固有の機能を使用しているアプリケーションでは、コードの変更や追加が必要な場合があります。ホストアドレス形式を使用したり、バークレイ UNIX の特権ポートを使用するアプリケーションがこれに当たります。
ライブラリ内部や個々のソケット仕様に依存していたり、特定のトランスポートアドレスに依存するアプリケーションは、移行の手間も大きく、本質的な変更が必要な場合もあります。
アプリケーションがトランスポート独立になるため、より多くのトランスポート上で実行できます。
アプリケーションの効率を改善する新規インタフェースが使用できます。
バイナリレベルの互換性の影響は、ネイティブモードより少なくなります。
旧インタフェースは、将来のバージョンで使用できなくなる可能性があります。
ネットワーク関数は libc から外されました。コンパイル時には libnsl を明示的に指定して、ネットワーク・サービス・ルーチンをリンクする必要があります。
旧インタフェースの多くは libnsl ライブラリでもサポートされていますが、TCP と UDP でしか使用できません。それ以外の新たなトランスポートを利用するには、新インタフェースを使用する必要があります。
トランスポート独立にするには、アドレスを直接使用できません。すなわち、アプリケーションでアドレス変換を行う必要があります。
トランスポート独立型の RPC とトランスポート特定の RPC との主な相違点を表 4-11 に示します。TI-RPC と TS-RPC の比較については、「旧バージョンとの比較」 のサンプルプログラムを参照してください。
表 4-11 TI-RPC と TS-RPC の相違点
この節では、RPC ライブラリ関数を機能別にグループ化して示します。各グループ内では、旧バージョンと同じ関数、機能が追加された関数、旧バージョンにはなかった新規関数に分けて示します。
アスタリスクの付いた関数は、新バージョンへの移行期間はサポートされていますが、Solaris の将来のバージョンではなくなる可能性があります。
次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。
clnt_destroy clnt_pcreateerror *clntraw_create clnt_spcreateerror *clnttcp_create *clntudp_bufcreate *clntudp_create clnt_control clnt_create clnt_create_timed clnt_create_vers clnt_dg_create clnt_raw_create clnt_tli_create clnt_tp_create clnt_tp_create_timed clnt_vc_create  | 
次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。
svc_destroy svcfd_create *svc_raw_create *svc_tp_create *svcudp_create *svc_udp_bufcreate svc_create svc_dg_create svc_fd_create svc_raw_create svc_tli_create svc_tp_create svc_vc_create  | 
次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。
*registerrpc *svc_register *svc_unregister xprt_register xprt_unregister rpc_reg svc_reg svc_unreg  | 
次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。
*callrpc clnt_call *svc_getcaller - IP に基づくトランスポートでのみ使用可 rpc_call svc_getrpccaller  | 
次の関数の機能は旧バージョンと同じです。旧バージョンとの互換性を保つためにだけサポートされています。
*clnt_broadcast  | 
clnt_broadcast() は portmap サービスにだけブロードキャストできます。
portmap と rpcbind の両方にブロードキャストできる次の関数が現在の SunOS で使用できます。
rpc_broadcast  | 
TI-RPC ライブラリ関数は、portmap と rpcbind の両方で使用できますが、それぞれサービスが異なるため、次のように 2 組の関数が提供されています。
次の関数は portmap と共に使用します。
pmap_set pmap_unset pmap_getport pmap_getmaps pmap_rmtcall  | 
次の関数は rpcbind と共に使用します。
rpcb_set rpcb_unset rpcb_getaddr rpcb_getmaps rpcb_rmtcall  | 
次の関数の機能は旧バージョンと同じです。旧バージョンとの互換性を保つためにだけサポートされています。
authdes_create authunix_create authunix_create_default authdes_seccreate authsys_create authsys_create_default  | 
現バージョンの rpcbind ではタイムサービス (主として、安全な RPC のためにクライアント側とサーバー側の時間を同期させるときに使用) が提供されており、rpcb_gettime() 関数で利用できます。pmap_getport() と rpcb_getaddr() は、登録サービスのポート番号を取り出すときに使用します。サーバーでバージョンが 2、3、4 の rcpbind が実行されている場合には、rpcb_getaddr() を使用します。pmap_getport() はバージョン 2 が実行されている場合しか使用できません。
例 4-43 と 例 4-44 では、クライアント作成部分が TS-RPC と TI-RPC とでどう違うかを示します。どちらのプログラムも次のことを実行します。
UDP 記述子を作成します。
遠隔ホストの RPC 結合プロセスと通信してサービスアドレスを得ます。
遠隔サービスのアドレスを記述子に結合します。
クライアントハンドルを作成してタイムアウト値を設定します。
	struct hostent *h;
	struct sockaddr_in sin;
 int sock = RPC_ANYSOCK;
	u_short port;
	struct timeval wait;
 
	if ((h = gethostbyname( "host" )) == (struct hostent *) NULL)
{
		syslog(LOG_ERR, "gethostbyname failed");
		exit(1);
	}
 sin.sin_addr.s_addr = *(u_int *) hp->h_addr;
	if ((port = pmap_getport(&sin, PROGRAM, VERSION, "udp")) == 0) {
	 syslog (LOG_ERR, "pmap_getport failed");
		exit(1);
 } else
		sin.sin_port = htons(port);
	wait.tv_sec = 25;
	wait.tv_usec = 0;
	clntudp_create(&sin, PROGRAM, VERSION, wait, &sock);
 | 
TI-RPC では、UDP トランスポートは netid udp を持つものとみなします。netid はよく知られた名前でなくてもかまいません。
	struct netconfig *nconf;
	struct netconfig *getnetconfigent();
	struct t_bind *tbind;
 struct timeval wait;
 
	nconf = getnetconfigent("udp");
 if (nconf == (struct netconfig *) NULL) {
		syslog(LOG_ERR, "getnetconfigent for udp failed");
		exit(1);
 }
	fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
 if (fd == -1) {
		syslog(LOG_ERR, "t_open failed");
 	exit(1);
	}
	tbind = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
	if (tbind == (struct t_bind *) NULL) {
 	syslog(LOG_ERR, "t_bind failed");
		exit(1);
 }
	if (rpcb_getaddr( PROGRAM, VERSION, nconf, &tbind->addr, "host")
								== FALSE) {
		syslog(LOG_ERR, "rpcb_getaddr failed");
		exit(1);
	}
 cl = clnt_tli_create(fd, nconf, &tbind->addr, PROGRAM, VERSION,
                       0, 0);
	(void) t_free((char *) tbind, T_BIND);
	if (cl == (CLIENT *) NULL) {
		syslog(LOG_ERR, "clnt_tli_create failed");
		exit(1);
	}
 wait.tv_sec = 25;
	wait.tv_usec = 0;
	clnt_control(cl, CLSET_TIMEOUT, (char *) &wait);
 
 | 
例 4-45 と例 4-46 では、ブロードキャスト部分が旧バージョンと SunOS 5.3 とでどう違うかを示します。SunOS 4.x の clnt_broadcast() は SunOS 5.3 の rpc_broadcast() とほぼ同じです。大きく異なるのは、collectnames() 関数で重複アドレスを削除し、ブロードキャストに応答したホスト名を表示する点です。
statstime sw;
extern int collectnames();
 
clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,         
    	xdr_void, NULL, xdr_statstime, &sw, collectnames);
	...
collectnames(resultsp, raddrp)
	char *resultsp;
	struct sockaddr_in *raddrp;
{
	u_int addr;
	struct entry *entryp, *lim;
	struct hostent *hp;
	extern int curentry;
 
	/* 重複アドレスはカット */
 addr = raddrp->sin_addr.s_addr;
	lim = entry + curentry;
 for (entryp = entry; entryp < lim; entryp++)
		if (addr == entryp->addr)
			return (0);
	...
 /* ホスト名がわかればホスト名、わからなければアドレスを表示 */
	hp = gethostbyaddr(&raddrp->sin_addr.s_addr, sizeof(u_int),
	    AF_INET);
	if( hp == (struct hostent *) NULL)
		printf("0x%x", addr);
	else
 	printf("%s", hp->h_name);
}
 
 | 
例 4-46 は、TI-RPC におけるブロードキャストを示します。
statstime sw;
extern int collectnames();
 
rpc_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
     xdr_void, NULL, xdr_statstime, &sw, collectnames, (char *)
0);
	...
collectnames(resultsp, taddr, nconf)
	char *resultsp;
	struct t_bind *taddr;
	struct netconfig *nconf;
{
 struct entry *entryp, *lim;
	struct nd_hostservlist *hs;
 extern int curentry;
	extern int netbufeq();
 
	/* 重複アドレスはカット */
	lim = entry + curentry;
	for (entryp = entry; entryp < lim; entryp++)
		if (netbufeq( &taddr->addr, entryp->addr))
			return (0);
 ...
	/* ホスト名がわかればホスト名、わからなければアドレスを表示 */
	if (netdir_getbyaddr( nconf, &hs, &taddr->addr ) == ND_OK)
 	printf("%s", hs->h_hostservs->h_host);
	else {
 	char *uaddr = taddr2uaddr(nconf, &taddr->addr);
		if (uaddr) {
			printf("%s¥n", uaddr);
			(void) free(uaddr);
 	} else
			printf("unknown");
	}
}
netbufeq(a, b)
	struct netbuf *a, *b;
{
	return(a->len == b->len && !memcmp( a->buf, b->buf, a->len));
}
 |