クライアントとサーバーの接続が行われる前に、それぞれが t_open(3NSL) を使用してトランスポートプロバイダ (トランスポートエンドポイント) へのローカル接続を行い、t_bind(3NSL) によりその識別 (またはアドレス) を確立する必要があります。
多くのプロトコルでは XTI/TLI で定義されているサービスのサブセットの実行が可能です。各トランスポートプロバイダは提供するサービスを決定したり、サービスを制限したりする特性を持っています。トランスポート特性を定義しているデータは t_info 構造体で t_open(3NSL) によって返されます。表 3-6 は t_info 構造体のフィールドの一覧です。
表 3-6 t_info 構造体
フィールド |
内容 |
---|---|
addr |
トランスポートアドレスの最大サイズ |
options |
トランスポートユーザーとトランスポートプロバイダ間を送信可能なプロトコル固有オプションの最大バイト数 |
tsdu |
コネクションモードまたはコネクションレスモードで送信可能な最大メッセージサイズ |
etsdu |
トランスポート接続によって送信可能な優先データ最大メッセージサイズ |
connect |
接続の確立時にユーザー間で送信可能なユーザーデータの最大バイト数 |
discon |
接続の放棄型解放時にユーザー間で送信可能なユーザーデータの最大バイト数 |
servtype |
トランスポートプロバイダによりサポートされているサービスのタイプ |
XTI/TLI により定義されている 3 つのサービスタイプは以下の通りです。
T_COTS - トランスポートプロバイダはコネクションモードサービスをサポートしているが 、正常型解放機能を提供していない。接続の終了は放棄型解放によって行われ、送信されていないデータは破棄される。
T_COTS_ORD - トランスポートプロバイダは正常型解放機能を持つコネクションモードサービスを提供する。
T_CLTS - トランスポートプロバイダはコネクションレスモードサービスを提供する。
t_open(3NSL) により識別されるトランスポートプロバイダに関連付けが行えるのは 1 つのサービスのみです。
t_open(3NSL) はトランスポートエンドポイントのデフォルトプロバイダ特性を戻します。エンドポイントが開かれると変化する特性もあります。これはネゴシエーションを行ったオプションで発生します (オプションのネゴシエーションについてはこの章の以降のページで説明する)。t_getinfo(3NSL) はトランスポートエンドポイントの現在の特性を戻します。
ユーザーが選択したトランスポートプロバイダとエンドポイントを確立した後に、クライアントおよびサーバーは識別の確定を行う必要があります。これを行うのがトランスポートエンドポイントへトランスポートアドレスのバインドを行う t_bind(3NSL) です。サーバーの場合、このルーチンが接続要求待機にエンドポイントが使用されていることをトランスポートプロバイダへ通知します。
t_optmgmt(3NSL) はローカル管理フェーズ中に使用できます。ユーザーによるトランスポートプロバイダとのプロトコルオプション値のネゴシエーションを可能にします。各トランスポートプロトコルは quality-of-service パラメータなど独自のネゴシエーション可能なプロトコルオプションを定義します。オプションがプロトコル固有のものであるため、特定のプロトコル用に作成されたプログラムだけがこの機能を使用できます。
これらの機能の詳細を説明するためにクライアントおよびサーバーのローカル管理の必要条件を例に示します。例 3-3 ではクライアントプログラムで必要とされる定義を行ってから必要なローカル管理を行うステップを示しています。
#include <stdio.h> #include <tiuser.h> #include <fcntl.h> #define SRV_ADDR 1 /* サーバーのアドレス*/ main() { int fd; int nbytes; int flags = 0; char buf[1024]; struct t_call *sndcall; extern int t_errno; if ((fd = t_open("/dev/exmp", O_RDWR, (struct t_info *),NULL)) == -1) { t_error("t_open failed"); exit(1); } if (t_bind(fd, (struct t_bind *) NULL, (struct t_bind *) NULL) == -1) { t_error("t_bind failed"); exit(2); }
t_open(3NSL) の最初の引数はトランスポートプロトコルの識別を行うファイルシステムオブジェクトのパスです。/dev/exmp は汎用通信ベースのトランスポートプロトコルの識別を行う特別なファイル名の例です。2 つ目の引数 O_RDWR は読み書き可能なオープンを指定しています。3 つ目の引数は t_info 構造体を指定し、トランスポートのサービス特性が戻されます。
このデータはプロトコルに依存しないソフトウェアに適しています (「プロトコルに依存しない処理に関する指針」を参照)。この例では NULL ポインタが渡されています。例 3-3 においては、トランスポートプロバイダは以下の特性を持っている必要があります。
例は正常型解放を使用しているためトランスポートプロバイダは T_COTS_ORD
サービスタイプをサポートする。
トランスポートプロバイダはプロトコル固有オプションを必要としない。
ユーザーが T_COTS_ORD
以外のサービスを必要とする場合、別のトランスポートプロバイダをオープンすることが可能です。T_CLTS
サービス要請についての例は 「読み取り/書き込み用インタフェース」 で説明しています。
t_open(3NSL) は後に続くすべての XTI/TLI 関数呼び出しで使用されるトランスポートエンドポイントファイルハンドルを戻します。識別子はトランスポートプロトコルファイルをオープンして得られるファイル記述子です (open(2) を参照)。
クライアントはエンドポイントにアドレスを割り当てるため t_bind(3NSL) を呼び出します。t_bind(3NSL) の最初の引数はトランスポートエンドポイントハンドルです。2 つ目の引数はエンドポイントへバインドするアドレスを示す t_bind 構造体を指定します。3 つ目の引数はプロバイダがバインドしたアドレスを示す t_bind 構造体を指定します。
クライアントのアドレスは多くの場合、他の処理がアクセスを行わないため重要性を持ちません。そのため t_bind(3NSL) への 2 つ目および 3 つ目の引数は NULL です。2 つ目の NULL 引数がユーザー用のアドレスの選択のためトランスポートプロバイダへ指示を行います。
t_open(3NSL) または t_bind(3NSL) が失敗した場合、プログラムは stderr による適切なエラーメッセージを表示するために t_error(3NSL) を呼び出します。整数型の外部変数 t_error(3NSL) はエラー値に割り当てられます。エラー値のセットが tiuser.h に定義されています。
t_error(3NSL) は perror(3C) と類似しています。トランスポート機能エラーがシステムエラーの場合、t_errno(3NSL) は TSYSERR に設定され、errno は適切な値に設定されます。
サーバーの例においても接続要求待機を行うためにトランスポートエンドポイントを確立する必要があります。 例 3-4 では定義とローカル管理を行うステップを例で示しています。
#include <tiuser.h> #include <stropts.h> #include <fcntl.h> #include <stdio.h> #include <signal.h> #define DISCONNECT -1 #define SRV_ADDR 1 /* サーバーのアドレス*/ int conn_fd; /* ここで接続の確立*/ extern int t_errno; main() { int listen_fd; /* トランスポートエンドポイント待機*/ struct t_bind *bind; struct t_call *call; if ((listen_fd = t_open("/dev/exmp", O_RDWR, (struct t_info *) NULL)) == -1) { t_error("t_open failed for listen_fd"); exit(1); } if ((bind = (struct t_bind *)t_alloc( listen_fd, T_BIND, T_ALL)) == (struct t_bind *) NULL) { t_error("t_alloc of t_bind structure failed"); exit(2); } bind->qlen = 1; /* * プロバイダのアドレスの形式を推測するため * このプログラムはトランスポートに依存する */ bind->addr.len = sizeof(int); *(int *) bind->addr.buf = SRV_ADDR; if (t_bind (listen_fd, bind, bind) < 0 ) { t_error("t_bind failed for listen_fd"); exit(3); } #if (!defined(_XOPEN_SOURCE) ||(_XOPEN_SOURCE_EXTENDED -0 != 1)) /* * 正しいアドレスがバインドされているかどうか * * XTI の場合このテストは不要 */ if (bind->addr.len != sizeof(int) || *(int *)bind->addr.buf != SRV_ADDR) { fprintf(stderr, "t_bind bound wrong address¥n"); exit(4); } #endif
クライアント同様、サーバーはまず選択したトランスポートプロバイダとトランスポートエンドポイントを確立するため t_open(3NSL) を呼び出します。エンドポイント listen_fd は接続要求待機を行うために使用されます。
次にサーバーはアドレスをエンドポイントへバインドします。アドレスは各クライアントがサーバーへアクセスする際に使用されます。2 つ目の引数はエンドポイントへバインドするアドレスを指定する t_bind 構造体を指します。t_bind 構造体は以下の形式です。
struct t_bind { struct netbuf addr; unsigned qlen; }
addr はバインドされたアドレスを示し、qlen は未処理の接続要求の最大件数を指定します。すべての XTI 構造および定数定義は xti.h を介しアプリケーションプログラムで使用可能になります。すべての TLI 構造体および定数定義は tiuser.h に格納されます。
アドレスは以下の形式で netbuf 構造体で指定されます。
struct netbuf { unsigned int maxlen; unsigned int len; char *buf; }
maxlen はバッファーの最大長をバイト単位で指定、len はバッファー内のデータのバイト長を指定、そして buf はデータを格納しているバッファーを指します。
t_bind 構造体では、データはトランスポートアドレスを識別します。qlen は待機可能な接続要求の最大数を指定します。qlen の値が正の場合、エンドポイントを接続要求の待機に使用することが可能となります。t_bind(3NSL) は、ただちにバイトされたアドレスに各接続要求の待機を行うようトランスポートプロバイダに指示します。サーバーは 1 つずつ接続要求の待機を解除し、受け付けまたは拒否を行う必要があります。次の接続要求を受信する前に 1 つの接続要求の処理および応答を行うサーバーの場合、qlen の値は 1 が適切です。応答を行う前に複数の接続要求の待機を解除するサーバーの場合は、より長い待ち行列を指定する必要があります。この例のサーバーでは、一度に 1 つの接続要求の処理しか行わないため、qlen は 1 に設定してあります。
t_alloc(3NSL) は t_bind 構造体を割り当てるために呼び出されます。t_alloc(3NSL) には 3 つの引数があります。トランスポートエンドポイントのファイル記述子、割り当てる構造体の識別子、そして割り当てる netbuf バッファーを指定するフラグです ( netbuf バッファーを使用する場合)。T_ALL はすべての netbuf バッファーの割り当てを指定し、この例では addr バッファーが割り当てられる要因となります。バッファーのサイズは自動的に決定され、maxlen に格納されます。
各トランスポートプロバイダは個別にアドレス空間を管理します。トランスポートプロバイダには複数のトランスポートエンドポイントに同じトランスポートアドレスをバインドするものと、各エンドポイントに固有のアドレスをバインドするものがあります。XTI と TLI のアドレスバインド方法には大きく異なる部分があります。
TLI のルールでは、プロバイダが要求されたアドレスのバインドが可能かを判定します。バインドが行えない場合、そのアドレス空間で別の有効アドレスを捜しトランスポートエンドポイントにバインドします。アプリケーションプログラムは、バインドされたアドレスが事前にクライアントに通知されたものと同一であることをチェックする必要があります。XTI ではプロバイダが要求されたアドレスのバインドを行えないと判定した場合、t_bind(3NSL) をエラーで終了します。
t_bind(3NSL) が成功した場合、プロバイダは接続要求の待機を開始し、通信の次のフェーズに移ります。