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

     前  次    新規ウィンドウで目次を開く    PDFとして表示 - 新規ウィンドウ  Adobe Readerを入手 - 新規ウィンドウ
コンテンツはここから始まります

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

このトピックには次の項が含まれます:

 


会話型通信の概要

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

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

図7-1の銀行業務のオンライン・アプリケーションを例に、Oracle Tuxedo ATMIアプリケーションで行われる会話型通信について説明します。この例では、銀行の顧客が過去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)

表7-1は、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 ATMI C言語関数リファレンス』の「tpconnect(3c)」を参照してください。
システムは、TPSVCINFO構造体のフラグ・メンバーを使用して呼び出されたサービスに通知します。

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

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

リスト7-1は、tpconnect()関数の使用方法を示しています。

リスト7-1 会話型接続の確立
#include atmi.h
#define FAIL -1
int cd1; /* Connection Descriptor */
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)

表7-2は、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 ATMI C言語関数リファレンス』の「tpsend(3c)」を参照してください。
flag
フラグの設定値。有効なフラグ設定については、『Oracle Tuxedo ATMI C言語関数リファレンス』の「tpsend(3c)」を参照してください。

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

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

リスト7-2は、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を指定すると呼出しは失敗し、tperrno(5)TPEINVALが設定されます。
呼び出された会話型サービスは、TPSVCINFOデータ構造体を介してdataおよびlenポインタを受け取ります。この構造体は、サービスが呼び出されたときにmain()関数によって渡されます。(リクエスト/レスポンス・サービスも同じ方法で、dataおよびlenポインタを受け取ります。)TPSVCINFOデータ構造体の詳細については、「サービスの定義」を参照してください。
len
データ・バッファの長さ。バッファが自己記述型(FMLバッファなど)の場合、lenに0を設定できます。NULLを指定すると呼出しは失敗し、tperrno(5)TPEINVALが設定されます。
revent
エラーの発生時(つまり、tperrnoTPEEVENTが設定された場合)に、設定されるイベント値を指すポインタ。有効なイベント値については、『Oracle Tuxedo ATMI C言語関数リファレンス』の「tprecv(3c)」を参照してください。
flag
フラグの設定値。有効なフラグについては、『Oracle Tuxedo ATMI C言語関数リファレンス』の「tprecv(3c)」を参照してください。

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

リスト7-3は、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()は失敗します。

例: 単純な会話の終了

図7-2は、正常に終了する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は、正常に終了する階層構造の会話を示しています。

図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 ATMI C言語関数リファレンス』の「tpdiscon(3c)」を参照してください。

 


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

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

会話型サービスとリクエスト/レスポンス型サービスでは、次の操作を行うことはできません。

 


会話型通信イベントの理解

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

表7-3は、イベント、そのイベントを受け取る関数、および各イベントの詳細な説明を示しています。

表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で呼び出されたこと)を示します。


  先頭に戻る       前  次