C 言語を使用した Oracle Tuxedo アプリケーションのプログラミング

     前  次    新しいウィンドウで目次を開く     
ここから内容の開始

会話型クライアントおよびサーバのコーディング

ここでは、以下の内容について説明します。

 


会話型通信の概要

会話型通信は Oracle Tuxedo システムのメッセージ交換のパラダイムで、人の会話に似た通信がクライアントとサーバ間で実装されています。この通信方法では、クライアント (開始プロセス) とサーバ (従属サーバ) 間で仮想接続が行われて、双方で会話の状態に関する情報が保持されます。この接続は、接続を終了するイベントが発生するまで継続します。

会話型通信では、クライアントとサーバ間に半二重接続が確立されます。半二重接続では、メッセージが 1 方向だけに送信されます。接続に関する制御は、開始プロセスから従属サーバへ、またはその逆に移ります。制御を持つプロセスがメッセージを送信でき、持たないプロセスは受信しかできません。

以下に銀行業務のオンライン アプリケーションを例に、Oracle Tuxedo アプリケーションで行われる会話型通信について説明します。この例では、銀行の顧客が過去 2 か月間の当座預金の明細書を要求しています。

図 7-1 銀行業務オンライン アプリケーションでの会話型通信

銀行業務オンライン アプリケーションでの会話型通信

  1. 顧客が過去 2 か月間の当座預金口座の明細書を要求します。
  2. 口座レコード管理システムは、この要求に対する応答として、当座預金口座の最初の月の明細書を送信します。次に、次の月の明細書を送信するかどうかを More プロンプトで確認します。
  3. 顧客は More プロンプトを選択して、次の月の明細書を要求します。
注意 : 口座レコード管理システムでは、状態情報を保持して、顧客が More プロンプトを選択した場合にどの明細書を送るのか認識できるようにする必要があります。
  1. 口座レコード管理システムは、次の月の明細書を送信します。

要求/応答型通信の場合と同じように、Oracle Tuxedo システムでは型付きバッファを使用してデータが渡されます。アプリケーションがバッファ タイプを認識できることが必要です。バッファ タイプの詳細については、「型付きバッファの概要」を参照してください。

会話型のクライアントおよびサーバには、次の特徴があります。

会話型通信は、次の点で要求/応答型通信と異なります。

 


アプリケーションへの参加

会話型クライアントは、サービスへの接続を確立する前に、tpinit() を呼び出してアプリケーションに参加する必要があります。詳細については、「クライアントのコーディング」を参照してください。

 


接続の確立

tpconnect(3c) 関数は、会話を行うための接続を確立します。

tpconnect() 関数の呼び出しには、次の文法を使用します。

int
tpconnect(char *name, char *data, long len, long flags)

次の表は、tpconnect() 関数の引数を示しています。

表 7-1 tpconnect( ) 関数の引数
引数
説明
name
会話型サービス名を指す文字型のポインタ。name に会話型サービスを指すポインタが指定されていない場合、呼び出しが失敗して -1 が返され、tperrno にエラー コード TPENOENT が設定されます。
data
データ バッファを指すポインタ。data 引数に、tpalloc() を使用して既に割り当てられているバッファを指すポインタを設定すると、接続の確立と同時にデータを送信することができます。バッファのタイプとサブタイプは、呼び出されたサービスで認識できなければなりません。data に NULL を設定して、送信データがないことを示すことができます。
呼び出された会話型サービスは、TPSVCINFO データ構造体を介して data および len ポインタを受け取ります。この構造体は、サービスが呼び出されたときに main() 関数によって渡されます。要求/応答型サービスも同じ方法で、data および len ポインタを受け取ります。TPSVCINFO データ構造体の詳細については、「サービスの定義」を参照してください。
len
データ バッファの長さ。バッファが自己記述型 (FML バッファなど) の場合、len に 0 を設定できます。
flag
フラグの設定値。有効なフラグの設定値については『Oracle Tuxedo C リファレンス』の「tpconnect(3c)」を参照してください。
システムは、TPSVCINFO 構造体のフラグ メンバーを使用して呼び出されたサービスに通知します。

tpconnect() によって接続が確立されると、Oracle Tuxedo システムから接続記述子 (cd) が返されます。この cd は、特定の会話で以降に送られるメッセージを識別するために使用されます。クライアントまたは会話型サービスは、複数の会話に同時に参加できます。最大 64 個の会話を同時に行うことができます。

tpconnect() 関数の呼び出しが失敗すると -1 が返され、対応するエラー コードが tperrno に設定されます。エラー コードについては、『Oracle Tuxedo C リファレンス』の「tpconnect(3c)」を参照してください。

次のサンプル コードは、tpconnect() 関数の使用方法を示しています。

コード リスト 7-1 会話型接続の確立
#include atmi.h
#define FAIL -1
int cd1; /* 接続記述子 */
main()
{
if ((cd = tpconnect(“AUDITC”,NULL,0,TPSENDONLY)) == -1) {
error routine
}
}

 


メッセージの送受信

Oracle Tuxedo システムで会話型接続が確立されると、開始プロセスと従属サーバ間の通信は送信呼び出しと受信呼び出しによって行われます。接続の制御を持つプロセスは、tpsend(3c) 関数を使用してメッセージを送信できます。制御がないプロセスは、tprecv(3c) 関数を使用してメッセージを受信できます。

注意 : 発信元 (クライアント) は、最初に tpconnect() 呼び出しの TPSENDONLY または TPRECVONLY フラグを使用して、どのプロセスが制御を持っているのかを判別します。TPSENDONLY は、発信元が制御を持つことを示します。TPRECVONLY は、呼び出されたサービスに制御が渡されたことを示します。

メッセージの送信

メッセージを送信するには、tpsend(3c) 関数を使用します。この関数には、次の文法を使用します。

int
tpsend(int cd, char *data, long len, long flags, long *revent)

次の表は、tpsend() 関数の引数を示しています。

表 7-2 tpsend( ) 関数の引数
引数
説明
cd
tpconnect() 関数で返される接続記述子。データが送信される接続が識別されます。
data
データ バッファを指すポインタ。data 引数に、tpalloc() を使用して既に割り当てられているバッファを指すポインタを設定すると、接続の確立と同時にデータを送信することができます。バッファのタイプとサブタイプは、呼び出されたサービスで認識できなければなりません。data に NULL を設定して、送信データがないことを示すことがきます。
呼び出された会話型サービスは、TPSVCINFO データ構造体を介して data および len ポインタを受け取ります。この構造体は、サービスが呼び出されたときに main() 関数によって渡されます。要求/応答型サービスも同じ方法で、data および len ポインタを受け取ります。TPSVCINFO データ構造体の詳細については、「サービスの定義」を参照してください。
len
データ バッファの長さ。バッファが自己記述型 (FML バッファなど) の場合、len に 0 を設定できます。data に値が設定されていない場合、この引数は無視されます。
revent
エラーの発生時 (つまり、tperrno(5)TPEEVENT が設定された場合) に、設定されるイベント値を指すポインタ。有効なイベント値については、『Oracle Tuxedo C リファレンス』の「tpsend(3c)」を参照してください。
flag
フラグの設定値。有効なフラグ設定については、『Oracle Tuxedo C リファレンス』の「tpsend(3c)」を参照してください。

tpsend() 関数の呼び出しが失敗すると -1 が返され、対応するエラー コードが tperrno(5) に設定されます。エラー コードについては、『Oracle Tuxedo C リファレンス』の「tpsend(3c)」を参照してください。

tpsend() 関数を呼び出すたびに、制御を渡す必要はありません。一部のアプリケーションでは、tpsend() の呼び出しを認められているプロセスが、制御をほかのプロセスに渡すまで、現在のタスクで必要な回数だけ呼び出しを実行できます。ただし、プログラムのロジックによっては、会話が継続する間は常に 1 つのプロセスが接続の制御を持たなければならないアプリケーションもあります。

次のサンプル コードは、tpsend() 関数の呼び出し方法を示しています。

コード リスト 7-2 会話モードでのデータ送信
if (tpsend(cd,line,0,TPRECVONLY,revent) == -1) {
(void)userlog(“%s: tpsend failed tperrno %d”,
argv[0],tperrno);
(void)tpabort(0);
(void)tpterm();
exit(1);
}

メッセージの受信

オープン接続を介してデータを受信するには、tprecv(3c) 関数を使用します。この関数には、次の文法を使用します。

int
tprecv(int cd, char **data, long *len, long flags, long *revent)

次の表は、tprecv() 関数の引数を示しています。

引数
説明
cd
接続記述子。従属プログラムで呼び出しを行う場合は、cd 引数に、そのプログラムの TPSVCINFO 構造体に指定されている値を設定します。発信元のプログラムで呼び出しを行う場合は、cd 引数に、tpconnect() 関数で返される値を設定します。
data
データ バッファを指すポインタ。data 引数は、tpalloc() を使用して既に割り当てられているバッファを指す必要があります。バッファのタイプとサブタイプは、呼び出されたサービスで認識できなければなりません。NULL は指定できません。NULL を指定すると呼び出しは失敗し、tperrno(5)TPEINVAL が設定されます。
呼び出された会話型サービスは、TPSVCINFO データ構造体を介して data および len ポインタを受け取ります。この構造体は、サービスが呼び出されたときに main() 関数によって渡されます。要求/応答型サービスも同じ方法で、data および len ポインタを受け取ります。TPSVCINFO データ構造体の詳細については、「サービスの定義」を参照してください。
len
データ バッファの長さ。バッファが自己記述型 (FML バッファなど) の場合、len に 0 を設定できます。NULL は指定できません。NULL を指定すると呼び出しは失敗し、tperrno(5)TPEINVAL が設定されます。
revent
エラーの発生時 (つまり、tperrnoTPEEVENT が設定された場合) に、設定されるイベント値を指すポインタ。有効なイベント値については、『Oracle Tuxedo C リファレンス』の「tprecv(3c)」を参照してください。
flag
フラグの設定値。有効なフラグについては、『Oracle Tuxedo C リファレンス』の「tprecv(3c)」を参照してください。

処理が成功すると、*data が受信データを指し、len にバッファのサイズが格納されます。lentprecv() を呼び出す前のバッファの合計サイズより大きい場合、バッファのサイズは変更されていて、len はバッファの新しいサイズを示しています。len 引数が 0 の場合、受信データがないことを示します。

次のサンプル コードは、tprecv() 関数の使用方法を示しています。

コード リスト 7-3 会話型でのデータ受信
if (tprecv(cd,line,len,TPNOCHANGE,revent) != -1) {
(void)userlog(“%s: tprecv failed tperrno %d revent %ld”,
argv[0],tperrno,revent);
(void)tpabort(0);
(void)tpterm();
exit(1);
}

 


会話の終了

次の場合、接続が切断されて会話が正常に終了します。

注意 : tpreturn() 関数については、「クライアントおよびサーバへの要求/応答のコーディング」を参照してください。

以下の節では、会話を正常に終了する方法について、2 つの例を挙げて説明します。これらの会話には、tpreturn() 関数を使用するグローバル トランザクションは含まれていません。

最初の例では、2 つのコンポーネント間の単純な会話を終了する方法を示します。2 番目の例では、会話が階層構造になっている複雑な会話を終了する方法を示します。

接続がオープンになっているときに会話を終了すると、エラーが返されます。その場合、tpcommit() または tpreturn() は失敗します。

例: 単純な会話の終了

次の図は、正常に終了する A と B 間の単純な会話を示しています。

図 7-2 正常に終了する単純な会話

正常に終了する単純な会話

次の順序で処理が行われます。

  1. A は、TPSENDONLY フラグで tpconnect() を呼び出して接続を設定します。このフラグは、B が会話の受信側であることを示します。
  2. A は TPRECVONLY フラグで tpsend() を呼び出して、接続の制御を B に移します。その結果、TPEV_SENDONLY イベントが生成されます。
  3. B が次に tprecv() を呼び出すと -1 が返され、tperrno(5)TPEEVENT が設定されてます。revent 引数に TPEV_SENDONLY が返されて、制御が B に移ったことが示されます。
  4. B は、rvalTPSUCCESS を設定して tpreturn() を呼び出します。この呼び出しにより、A に対して TPEV_SVCSUCC イベントが生成され、接続が正常に切断されます。
  5. A は、tprecv() を呼び出して、イベントが発生したことと会話が終了したことを認識します。イベント TPEV_SVCFAIL が発生した場合でも、この tprecv() への呼び出しでデータを受信できます。
注意 : この例では、A はクライアントまたはサーバのどちらでもかまいませんが、B はサーバでなければなりません。

例: 階層構造の会話の終了

次の図は、正常に終了する階層構造の会話を示しています。

図 7-3 接続の階層構造

 接続の階層構造

この例では、サービス B は会話のメンバーで、2 番目のサービス C との接続を開始しています。つまり、A - B 間と B - C 間という 2 つのアクティブな接続が存在しています。B がこの両方の接続を制御している場合に tpreturn() の呼び出しを行うと、呼び出しは失敗し、すべてのオープン接続に TPEV_SVCERR イベントが通知され、接続が切断されます。

両方の接続を正常に終了するには、次の処理を順に行います。

  1. B は、C との接続に TPRECVONLY フラグを設定して tpsend() を呼び出し、B - C 間の接続の制御を C に渡します。
  2. C は、状況に応じて rval に TPSUCCESSTPFAIL、または TPEXIT を設定して、tpreturn() を呼び出します。
  3. B は、tpreturn() を呼び出し、A にイベント (TPEV_SVCSUCC または TPEV_SVCFAIL) を通知します。
注意 : 会話型サービスは、別のサービスと通信するために要求/応答型の呼び出しを行うことができます。そのため、前述の例では、B から C への呼び出しに tpconnect() ではなく tpcall() または tpacall() を使用することもできます。ただし、会話型サービスが tpforward() を呼び出すことはできません。

会話の切断

エラーの発生により接続を終了する唯一の方法は、tpdiscon(3c) 関数を呼び出すことです。これは、「プラグを抜くこと」と同じです。この関数を呼び出すことができるのは、会話の開始プロセス (クライアント) だけです。

注意 : この方法で会話を終了することはお勧めしません。アプリケーションを正常に終了するには、従属サーバで tpreturn() 関数を呼び出します。

tpdiscon() 関数の呼び出しには、次の文法を使用します。

int
tpdiscon(int cd)

cd 引数は、接続が確立したときに tpconnect() 関数によって返される接続記述子を指定します。

tpdiscon() 関数は、接続の相手側のサービスに対して TPEV_DISCONIMM イベントを生成し、cd を無効にします。トランザクションが実行中の場合、そのトランザクションはアボートし、データは失われます。

cd で接続の開始側と識別されていないサービスから tpdiscon() が呼び出されると、その呼び出しは失敗し、エラー コード TPEBADDESC が生成されます。

イベントおよびエラー コードの全リストとその説明については、『Oracle Tuxedo C リファレンス』の「tpdiscon(3c)」を参照してください。

 


会話型のクライアントおよびサーバのビルド

次のコマンドを使用して、会話型のクライアントおよびサーバをビルドします。

会話型サービスと要求/応答型サービスでは、次の操作を行うことはできません。

 


会話型通信イベント

Oracle Tuxedo システムの会話型通信では、5 つのイベントが認識されます。これらのイベントはすべて tprecv() に通知でき、そのうちの 3 つは tpsend() にも通知できます。

次の表は、イベント、そのイベントを受け取る関数、および各イベントの簡単な説明を示しています。

表 7-3 会話型通信イベント
イベント
イベントを受け取る関数
説明
TPEV_SENDONLY
tprecv()
接続の制御が渡されました。この時点で、このプロセスは tpsend() を呼び出すことができます。
TPEV_DISCONIMM
tpsend()
tprecv()tpreturn()
接続は既に切断され、通信を継続することはできません。tpdiscon() 関数はこのイベントを接続の開始側に通知します。従属サービスとの接続がオープンしたままになっている場合に、tpreturn() が呼び出されたときは、このイベントをすべてのオープン接続に送信します。接続はエラーが原因で切断されます。トランザクションが存在している場合は、アボートします。
TPEV_SVCERR
接続の開始側が受信します。通常は、従属プログラムが接続の制御を持たない場合に、tpreturn() を呼び出したことを示します。
tprecv()
接続の開始側が受信します。従属プログラムが TPSUCCESS または TPFAIL、および妥当なデータ バッファを使用して tpreturn() を呼び出したが、エラーが発生して呼び出しが完了しなかったことを示します。
TPEV_SVCFAIL
接続の開始側が受信します。従属プログラムが接続の制御を持たない場合に tpreturn() を呼び出し、TPFAIL または TPEXIT、およびデータなしで tpreturn() が呼び出されたことを示します。
tprecv()
接続の開始側が受信します。従属サービスの処理が正常に終了しなかったこと (つまり、tpreturn()TPFAIL または TPEXIT で呼び出されたこと) を示します。
TPEV_SVCSUCC
tprecv()
接続の開始側が受信します。従属サービスの処理が正常に終了したこと (つまり、tpreturn()TPSUCCESS で呼び出されたこと) を示します。


  ページの先頭       前  次