Tivoli Service Desk 6.0 Developer's Toolkit Script プログラミングの手引き
この章は、TSD Script ネットワーキング拡張ステートメントを使用してネットワーク上で通信するために必要な基本的概念を紹介するように設計されます。この章では、特殊なネットワーキングの概念および TSD Script ネットワーキング・ステートメントおよび定数についても説明します。
こうした TSD Script ステートメントは、インストールされたアプリケーションのソース・コードをカスタマイズするため、あるいは独自のカスタム TSD Script 配布アプリケーションを作成するために使用することができます。
この章では TSD Script 言語およびネットワーキングの原理についてある種の基本的側面について触れますが、その両方に分野に精通しておられることが前提です。アプリケーションを変更しようとしている場合には、他のカスタマイズされたアプリケーションをもつ方、あるいは TSD Script および Developer's Toolkit を使用したことがある方と一緒に作業することもできます。
TSD Script 言語に組み込まれているステートメントは、ネットワーキング・アーキテクチャーの次の 2 つの特殊なタイプを考慮したものになっています。
この章での TSD Script ネットワーキング・サービスについての説明は、一般的に両方のアーキテクチャーに適用することができます。 これらのアーキテクチャー間に相違が存在する場合には、それについて説明します。
ネットワーク上のコンピューター間の対話を説明するために使用される多くの用語があります。 こうした用語の一部またはすべてをよく理解しておられるかもしれませんが、ここでは特に TSD Script ネットワーキング拡張で使用する場面に限定します。
両方向通信 は、2 つのマシンがそれぞれクライアントとサーバーの両方の役割を果たす時に行なわれます。つまり、マシン A (クライアント) は、マシン B (サーバー) にある種のサービスを実行するように要求することができます。 同様に、マシン B が役割を切り換え、マシン A に対してある種のサービスを実行するように要求することによって、クライアントとなることができます。「逆接続 」の定義も参照してください。「ピアツーピア」を参照してください。
クライアントは、サーバーからのサービスを要求するアプリケーションです。クライアントの例として、ネットワーク上でファイル・サーバーと接続しているワークステーションがあります。接続は、クライアントによって開始されます。
接続は、クライアントとサーバーとの間の論理リンクです。
イベント・ハンドラーは、非同期イベントを処理するように設計された特殊な TSD Script 機能です。サーバー上で稼働するイベント・ハンドラーは、ネットワークからのサービス要求を処理します。
各接続にはハンドルがあります。ハンドルには、クライアント・マシンについての情報およびサーバーが提供するサービスについての情報が含まれています。
TSD Script サーバーは、サービスを提供するネットワーク・コンピューター上で実行する TSD Script プロセスです。
ローカル・イベント・ハンドラーは、ローカル・マシン上で稼働するイベント・ハンドラーです。 このイベント・ハンドラーが別のマシンからの要求をサービス中の場合には、マシンは、サーバーです。
NETx ステートメント (すなわち拡張は)、接頭部 NET で始まる TSD Script ステートメントです。 これらのステートメントは、TSD Script アプリケーションがネットワーク上で通信できるようにするために作成されました。
対等環境は、1 つのマシンがクライアントとサーバーの両方の役割を演じることができるような環境です。
イベント・ハンドラーを登録すると、ハンドラーがイベント・ソースに関連付けられます。
逆接続は、ピアツーピア環境において、サーバーがクライアントとサーバーの役割を効果的に切り換えることによって、クライアントにある種のサービスを実行するように要求した時に確立することができます。この通信を処理するために、ローカル・サーバーとリモート・サーバーの間に逆接続が確立されます。
サーバーは、クライアントにサービスを提供するマシンです。サーバーの例にネットワーク・プリンターがあります。
サービスは、サーバーによって実行される機能です。プリンターがサーバーの場合には、提供されるサービスは印刷です。
イベント・ハンドラーは、イベント・ドリブン環境をサポートするために TSD Script および Developer's Toolkit 全体で使用されます。イベント・ドリブン環境では、イベント (キーストローク、マウス・クリック、ネットワーク・メッセージなど) は、アプリケーションによる応答 (新規ダイアログ・ボックスのオープンやフィールド中の項目の選択) を起動します。イベントを処理するには、各アプリケーションは特にそれ用に設計されたイベント・ハンドラーを使用します。
イベント・ハンドラーを使用するアプリケーションは、ネットワーク・イベントを要求したり、「ポーリング」したりする必要はありません。 通常、イベント・ハンドラーは、イベントが発生するまで「スリープ」し (アクティブでなく)、イベントが発生してから、サービス要求を処理します。
1 つのサーバーが複数のイベント・ハンドラーをもつことが可能です。各イベント・ハンドラーは、特定のサービスまたは 1 セットの関連サービス (この章で後で説明) を提供するように設計されています。
イベント・ハンドラーは、TSD Script プログラムのルーチン・セクションで定義されます。 ネットワーク・イベント・ハンドラーは、タイプ NETCONNECTION として宣言しなければなりません。
このイベント・ハンドラーのタイプは、デフォルト・タイプの WINDOW とは異なっています。タイプは使用される $Handle を決定するので、NETx ステートメントではタイプ NETCONNECTION のイベント・ハンドルしか使用することができません。
NETCONNECTION EVENT TalkConnectEvent(REF whdl: WINDOW )IS
イベント・ハンドラーを定義する時には、次のセクションで説明するようにそのサービスも登録しなければなりません。 イベント・ハンドラーを登録すると、ハンドラーがイベント・ソースに関連付けられます。
イベント・ハンドラーを登録するために使用できる 2 つの異なるステートメントがあります。
NetRegister で登録されたイベント・ハンドラーは、 NetRegister イベント・ハンドラーと呼ばれています。 NetListen で登録されたイベント・ハンドラーは、 NetListenイベント・ハンドラーと呼ばれています。
この章では、「標準」イベント・ハンドラーとしてよく使用される NetRegister に焦点を当てその使用について説明します。 イベント・ハンドラーのカスタマイズについては、この章の「拡張ステートメント」のセクションを参照してください。
サーバーがサービス要求を受信して処理するには、サーバーでイベント・ハンドラーを登録しなければなりません。 NetRegister でイベント・ハンドラーを登録するには、次の構文を使用してください。
NetRegister( TalkConnectEvent, 'Talk' );
イベント・ハンドラーを登録する時には、それが提供するサービスの名前を指定します。 サービスとは、イベント・ハンドラーによって実行されるアクションのカテゴリーです。
次の例では、TalkConnectEvent ネットワーク・イベント・ハンドラーに定義されたサービスの名前は Talk です。
NETCONNECTION EVENT TalkConnectEvent(REF whdl: WINDOW )IS ACTIONS . .. END; NetRegister( TalkConnectEvent, 'Talk' );
前に示したサービスに加えて、IP ポートを指定するポート番号拡張がサポートされています。ポート番号は次のものをコントロールします。
デフォルトのポートは 5001 で、デフォルトのサービスは asenet/tcp です。サービスがサービス・ファイルにある場合には、デフォルト番号の代わりに asenet/tcp が使用されます。
ポート番号は、次のコマンドによってコマンド・プロンプトに指定することができます。
/p=nnn
コマンド・プロンプトから出されたポート番号は、デフォルトのポートおよびデフォルトのサービスを指定変更します。
注: クライアントとサーバーでポート番号が同じでなければなりません。
ゼロの長さのストリング ('') または $Unknown として定義されたサービスをもつイベント・ハンドラーを作成することができます。 このタイプのサービスは、ワイルドカード・サービスと呼ばれています。
サーバー上でワイルドカード・サービスが定義されている時には、サーバーが一致するサービス名を見つけることができないような要求であっても、サーバーは、クライアントによって指定されたその要求をサービスします。
クライアント上にもワイルドカード・サービスを定義することができます。この場合には、サーバーは、'' か $Unknown のいずれかのサービス名をもつサービスを必要とします。
注: NetRegister ステートメントによってイベント・ハンドラーを登録する時にのみ、ワイルドカード・サービスを定義することができます。 (NetListen では、常にワイルドカード・サービスが使用されます。)
イベント・ハンドラーを登録する時には、サーバー上でサービスのテンプレートが定義されます。このテンプレートには、コードのルーチン・セクション中のイベント・ハンドラーの定義からの情報と イベント・ハンドラーが登録された時に指定された情報の両方が含まれます。
テンプレートは、接続が要求されるまで記憶域に保留されています。要求があると、テンプレート中の情報が使用され、接続のためのサービスが具体化されます。
テンプレートに対しては次の 2 種類の基本的変更を行うことができます。
テンプレートに変更が必要になった時にはいつでも、イベント・ハンドラーを再登録するか、あるいはそのサービスを登録することができます。イベント・ハンドラーを再登録すると、新規パラメーター値が即時に適用されます。 テンプレートに対してオープンされたすべての新規接続では、新しい値が使用されることになります。既存の接続は、テンプレートへの変更の影響を受けません。
注意: 元のテンプレートに指定されている通りにサービス名を指定しなければなりません。 さもないと、NetRegister ステートメントによってイベント・ハンドラー用に新規のテンプレートが作成され、既存のテンプレートは変更されません。
テンプレートが作成されると、そのテンプレートは、即時に、また継続的にサービス要求を受け入れられるようになります。しかし、サービス要求に応答しないようにいつでもテンプレートを停止することができます。これを行うには、次のように特殊なイベント・ハンドラー $NullHandler によってサービスを再登録しなければなりません。
NetRegister ($Nullhandler, 'service');
この構文では、"service" は、停止したいイベント・ハンドラーに関連したサービスの名前です。
サービスを $NullHandler で再登録すると、テンプレートからの将来のサービス要求は拒否されますが、テンプレートを使用する既存の接続は影響を受けません。
サーバーを再始動する必要がある場合には、イベント・ハンドラーおよびそのサービスを再登録しなければなりません。
イベント・ハンドラーは、多くの異なるクライアントとの接続をサービスすることができます。単純に接続ハンドルを調べるだけでは、実行されているサービスを判断することが困難な場合があります。
同様に、どのサーバーがサービスを実行しているか、またどのクライアントがサービスを受けているかを判断することも困難な場合があります。 これは特に NetListen イベント・ハンドラーの場合に該当します (このハンドラーは、受け取ったすべてのサービスの応答し、そのインスタンス・データを共用するものです)。
TSD Script は、ホスト (サーバー) についての情報および接続ハンドルからのサービスについての情報を入手するために使用できる 2 つのステートメントを提供します。
TSD Script はクライアント / サーバー・アーキテクチャーとともにピアツーピア・アーキテクチャーをサポートするので、NetGetHostName ステートメントは、リモート・マシンがサーバーの役割を演じているかに関係なく、そのマシンについての情報を入手するように設計されています。
クライアントで NetGetHostName ステートメントを呼び出した場合には、サーバーについての情報が得られます。サーバーで NetGetHostName ステートメントを呼び出した場合には、クライアントの名前が得られます。
どのサーバーにも多くの NETCONNECTION イベント・ハンドラーがあると考えられます。時として、これらの間でメッセージを受け渡しする必要がある場合があります。 こうしたメッセージをネットワーク全体で送信することは効率がよくないので、Developer's Toolkit は、 NetLoopBack ステートメントを提供しています。 NetLoopBack によって、メッセージをローカル・マシンからイベント・ハンドラーに送信することができます。
TSD Script ネットワーキング・アプリケーションは、接続基本のプロトコルを使用します。ネットワーク上のマシン間の対話は、接続を介して行われます。 サーバーが要求されたサービスをクライアントに提供するには、接続をオープンしなければなりません。
どの接続にも 3 つの要素があります。
接続を固有なものとするのは、これら 3 つの要素の組み合わせです。 接続をオープンおよびクローズする処理には、これらの要素のそれぞれが含まれます。
クライアントとサーバーとの間で複数の接続をオープンすることができます。しかし、サーバー / ポート上の特定のサービスに対しては、クライアントは 1 つの接続しかオープンすることができません。
注: クライアントとサーバー上の特定のイベント・ハンドラーとの間で接続がすでにオープンされている場合には、特定のサービスを要求すると、既存の接続のハンドルが戻されます。
イベント・ハンドラーおよびその関連サービスを登録すると、サーバーが指定されたサービスに対する要求を受け取ることができるようになります。
このセクションでは、接続のオープン処理について説明し、接続をオープンするために使用される手順をステップ別にリストします。
接続をオープンする手順および各ステップの説明は次の通りです。
クライアントがサービスを要求する時には、そのクライアントは、必要とするサービスの正確な名前を指定しなければなりません。 (サービスの名前は、イベント・ハンドラーがサーバーに登録された時に定義されます。) サーバーによって提供される使用可能なサービスの広範囲のリストはなく、またサービス名は大文字小文字の区別がありません。
ポートは、サービス・ストリングの一部として指定することができます。ポートを指定しない場合には、デフォルトが使用されます。
クライアントは、ゼロの長さのストリングか $Unknown のいずれかを指定することによって、ワイルドカード・サービスを要求することができます。 この場合には、要求を満たすために、サーバーは、NetListen か $Unknown のいずれかのサービス名のサービスをもっていなければなりません。
注: クライアントがサーバーで定義されていないサービスを要求した場合で、ワイルドカード・サービスまたは NetListen が定義されている場合には、サーバーは、クライアントの要求をワイルドカード・サービスと突き合わせます。
クライアントがサーバーと通信できない場合には、HOST_UNREACHABLE エラー・コード (-13) がクライアントに戻されます。
TSD Script サーバーが稼働中ない場合には、-13 HOST_UNREACHABLE エラー・コードがクライアントに戻されます。
接続がすでに確立されている場合には、クライアントに TRUE が戻されます。 接続のハンドルも戻されます。
一致するサービス名が見つかると、サーバーはクライアントにハンドルを戻します。 ハンドルは、サービスを提供するテンプレートのコピーを示します。クライアントがハンドルを受け取ると、そのクライアントは処理を続行することができます。
サーバーがワイルドカード・サービスを見つけた場合には、サーバーはクライアントにハンドルを戻します。 ハンドルは、ワイルドカード・サービスを提供するテンプレートのコピーを示します。クライアントがハンドルを受け取ると、そのクライアントは処理を続行することができます。
NetListen イベント・ハンドラーが見つかった場合には、クライアント・マシンとの接続を記述するハンドルがクライアントに戻されます。見つかった場合には、ハンドルが直接に NetListen イベント・ハンドラーを示します。クライアントは、ハンドルを受け取ると、イベント・データの処理を続行します。
NetListen イベント・ハンドラーが見つかった場合には、ステップ 10 に進みます。NetListen イベント・ハンドルが見つからなかった場合には、ステップ 8 に進みます。
サーバーで $MsgNetConnect が処理されると、接続がオープンされ、サービスが使用可能になります。
通常は接続のクローズ処理は、クライアントによって開始されます。しかし、サーバーもクローズ処理を開始することができます。 いずれの場合にも、接続をクローズするのに NetClose ステートメントが使用されます。
注: クライアントかサーバーのいずれかがダウンすると、それらの間の接続が解かれます。マシン間の通信を再確立するには、接続を再オープンしなければなりません。
クライアントが接続をクローズする時には、次の処理が行われます。
注: イベント・ハンドラーが NetListen イベント・ハンドラーである場合には、接続に特に定義されたインスタンス・データがありません。ハンドルがクローズ済みとしてマークされると、クローズ処理が完了します。 $MsgNetDestroy メッセージは送られません。
クライアントまたはサーバーのプログラムが終了した場合、あるいはネットワークで中断があった場合にも、ステップ 2 と 3 は起こります。
サーバーが接続のクローズを開始した場合には、サーバーからクライアントへ戻る方向の通信は存在しなくなります。
次回にクライアントがサーバーとの通信を試みると、クライアントは、クローズを検出し、「無効なハンドル」などのエラー・メッセージを生成します。
ピアツーピア環境では、NetClose は、クライアントとサーバーの両方の接続をクローズします。
インスタンス・データとは、接続に関連したユーザー定義の TSD Script データのことです。インスタンス・データは、接続が作成された時に作成され、接続がクローズされた時に破棄されます。
イベント・ハンドラーは、接続のすべてのメッセージとともにインスタンス・データに対する参照を受け取ります。インスタンス・データには接続に特有な情報が保管されます。
NetRegister でイベント・ハンドラーを登録すると、そのイベント・ハンドラーに対するインスタンス・データの初期値を指定することができます。テンプレートにオープンされたすべての接続は、指定した値に初期化されたインスタンス・データのコピー、あるいは初期値が提供されていない場合には $Unknown に初期化されたインスタンス・データのコピーを受け取ります。
インスタンス・データを指定する時には、次のことを思い出してください。
例:
connectionData is Record callCount = INTEGER; . . . END;
NETCONNECTION EVENT MyEvent (REF data: ConnectionData); ACTIONS When $Event IS $MsgCreate Then data.callCount=1; . . . END; END; StmtData : ConnectionData; NetRegister( MyEvent {StartDate}, 'Service');
接続がオープンされると、イベント・ハンドラーに定義されたインスタンス・データが接続用のテンプレートのコピー中で具体化され、その初期値を割り当てられます。この処理は、初期化と呼ばれています。
テンプレート中のインスタンス・データの値を $Unknown に設定した場合には、これは、初期化が行われないということを意味します。
インスタンス・データの初期値に値を設定しない場合にも、初期化は行われません。 値を設定しなかった場合には、初期値は $Unknown とみなされます。
1 つの NetRegister イベント・ハンドラーに複数の接続がオープンされることがあります。その接続のそれぞれにはインスタンス・データの独自のコピーがあります。
クライアントは、サーバーが前の要求を処理中であるかどうかに関係なくいつでもサーバーに要求を送ることができます。クライアントがサーバーからの応答を必要とする早さによっては、またクライアントがサーバーからデータが戻されることを必要とするかどうかによっては、クライアントは、 ブロック化ステートメントか非ブロック化ステートメントのいずれかによって要求を送ることができます。
サーバーは、要求を受け取ると、それを待ち行列に追加します。可能であれば、サーバーは、要求を受信順に処理します。(場合によっては、サーバーは、待ち行列中でブロック化メッセージを非ブロック化メッセージの前におくことがあります。)ネットワークの状態次第で、サーバーが要求をサービスできるようになるまでに、若干の時間がかかることがあります。
サーバーに送られるステートメントがブロック化ステートメントである場合には、サーバーで処理全体が完了するまで、クライアントに情報が戻されません。
SendMessage は、TSD Script 中の唯一のブロック化ステートメントです。
クライアントとサーバーの間のデッドロックを防止するために、いつでも接続でただ 1 つの SendMessage をアクティブにすることができます。
サーバーに送られるステートメントが非ブロック化ステートメントである場合には、このステートメントが待ち行列に追加された時に、サーバーは、「要求を受け取りました」ということを効果的に述べる応答をクライアントに戻します。クライアントは、処理を続行することができます。
幾つかの非ブロック化ステートメントがあります。
サーバーと通信するのに、ブロック化ステートメントか非ブロック化ステートメントのいずれかを選択することができます。いずれのタイプを選択しても、注意を要するある種の危険性があります。
TSD Script および Developer's Toolkit では、ハンドルは、ウィンドウおよびネットワーク活動を記録しておくために広く使用されます。
SendMessage または PostMessage のいずれかのステートメントによる接続にはハンドルが必要です。 前者はブロック化ステートメント、後者は非ブロック化ステートメントです。この特性は、クライアントおよびサーバーの動作を決定します。
サーバーは、クライアントによって要求されたサービスに一致するサービスをもつイベント・ハンドラー・テンプレートを見つけると、ハンドルをオープンします。ハンドルは、 $Handle パラメーターに含まれていて、接続をサービスするイベント・グループに渡されます。
サーバーは、接続のサーバー側をクローズすると、ハンドルをクローズ済みとしてマークします。クローズされた接続にアクセスしようとすると、エラー・メッセージ (Invalid_Handle) を受け取ります。
TSD Script の NETx ステートメントは、クライアント / サーバー・アーキテクチャーとピアツーピア・アーキテクチャーの両方で使用することができます。これら異なるアーキテクチャーを処理するために、NetConnect ステートメントには 2 つの形式があります。
クライアント / サーバー・アーキテクチャーでは、サーバーがクライアントの要求に応答してサービスを戻し、また、サーバーがクライアントの要求に応答して要求されたサービスを戻すことができるように、クライアントがホスト名およびサービスを指定する必要があります。
FUNCTION NetConnect(REF hndlHost: NETCONNECTION, .VAL hostName: STRING, . VAL service: STRING .): INTEGER;
ピアツーピア・アーキテクチャーでクライアントに応答するには、サーバーは、戻り接続をオープンしなければなりません。 ピアツーピア形式は、実際には戻り接続を作成するためのショートカットです。この形式は任意選択ですが、クライアント / サーバー形式を使用した場合と同じ結果を達成できる場合があります。
FUNCTION NetConnect( VAL hndlHost: NETCONNECTION ): INTEGER;
対等接続の場合には 1 つのハンドルしか必要としません。このハンドルには、接続についてのすべてのデータが含まれることになります。
NetGetHostName または NetGetService の詳細については、次の章を参照してください。
リモート・サーバーに応答を送信するには、$Handle 定数を使用してください。次の行で戻り接続を初期化することができます。
NetConnect( $Handle );
ここまでこの章では、NetRegister ステートメントを使用してイベント・ハンドラーを作成し、登録する「標準」メソッドに焦点を当ててきました。接続についてさらにコントロールを必要とするアプリケーションの場合には、TSD Script は、イベント・ハンドラーを登録するために一緒に使用できるステートメントの代替セットを提供します。これらのステートメントは次の通りです。
NetAccept は、NetRegister イベント・ハンドラーと非常によく似ています。
注: 機能的に完全にネットワーク化されたアプリケーションを実行するのに、NetListen または NetAccept のいずれかを使用する必要はありません。
このテーブルでは。NetRegister イベント・ハンドラーと NetListen イベント・ハンドラーの相違を要約しています。
NetListen は接続ごとに新規インスタンス・データの作成を必要としないので、NetListen を介した接続のオープン処理はいくぶん早くなります。
NetListen は、メッセージ間でコンテキストを維持する必要がない軽度のサービスにうまく適合しています。
比較アイテム | NetRegister | NetListen |
イベント・ハンドラーの数 | サーバー上では同時に多くの NetRegister イベント・ハンドラーが実行中でとなっていてもかまいません。 | NetListen イベント・ハンドラーは、サーバーに対して 1 つしか定義することができません。 |
登録済みサービス | NetRegister イベント・ハンドラーは、特定のサービスによって登録されます。クライアントは、サービス名で適切なテンプレートとの正確なサービス一致が得られるように要求しなければなりません。 | NetListen イベント・ハンドラーは、関連した特定サービスをもっていません。NetListen イベント・ハンドラーでのサービス一致は、サーバー上に一致する他のテンプレートがない時にのみ起こります。 |
テンプレート | NetRegister イベント・ハンドラーを登録すると、そのテンプレートが作成されます。テンプレートには、すべての接続特定情報が含まれます。 | NetListen イベント・ハンドラーを登録しても、作成されるテンプレートはありません。接続特定の情報は、アプリケーションが維持しなければなりません。 |
インスタンス・データ | 各接続には、インスタンス・データの独自のコピーがあります。 | イベント・ハンドラーには、定義された 1 セットのインスタンス・データがあります。 イベント・ハンドラーに対してオープンされるすべての接続は、このインスタンス・データを共用します。 |
ポート | サービスは、代替ポートを使用することができます。 | サービスは、デフォルトのポートしか使用できません。 |
サーバー上で同時に NetListen イベント・ハンドラーと NetRegister イベント・ハンドラーの両方が実行している場合があります。クライアントは、要求がどのようにサービスされるのかがわからないので、使用されるイベント・ハンドラーを特定して要求することはできません。
NetListen イベント・ハンドラーは、接続にコンテキスト情報が維持される必要がないサービスに使用されます。 NetListen イベント・ハンドラーは、 NetRegister イベント・ハンドラーより必要とするサーバー・リソースがいくぶん少なく、接続を少し早く作成します。
クライアントの要求は、他の一致 (ワイルドカード・テンプレートを含む) を見つけることができない場合にのみ、NetListen イベント・ハンドラーと一致します。クライアントは、サーバー上の NetListen イベント・ハンドラーにサービス名を送ります。 NetListen イベント・ハンドラーは、 NetGetService をもつサービスを見つけるためにハンドルを照会しなければなりません。
しかし、クライアントにはサービスがサーバーによってサポートされるかどうかの保証はありません。
各接続はそれぞれ他のオープンされている接続と同じインスタンス・データを共用できるので、同時に複数の NetListen 接続をオープンすることができます。したがって、 NetListen 接続をクローズしても、インスタンス・データが破棄されることはありません。
NetListen 接続をクローズする時には、クローズ中の接続用のリソースの終結処理を行う必要があります。
各 NetListen 接続のハンドルには、クライアントによって要求されている特定タイプのサービスについての情報があります。
NetListen イベント・ハンドラーは、インスタンス・データを各接続に関連付けません。代わりに、ご自身で各接続およびその活動を記録なさる必要があります。 個々の接続を記録できるということは、NetListen ステートメントを使用して、イベント・ハンドラーを登録することのさらなる利点です。
NetListen にオープンされた各接続では、NetListen イベント・ハンドラーに定義されたインスタンス・データのコピーが共用されます。インスタンス・データの特定セットをオープンされている NetListen 接続の 1 つに関連付けたい場合には、その接続に NetAccept ステートメントを呼び出すことができます。
注: NetAccept は、NetListen 接続の場合にのみ呼び出すことができます。 この接続にはそのハンドルを使用してアクセスします。 NetAccept は、接続に新規イベント・ハンドラーに関連付けることもできます。
接続に関連付けるインスタンス・データは、現在オープンされているか、または将来 NetListen イベント・ハンドラーにオープンされる可能性のある他のいずれの接続でも使用されません。NetAccept を呼び出すと、接続が更新されます。
同じホストとサービスの対に対するすべての要求は、直接に新規イベント・ハンドラーに向けられます。
注: NetListen と NetAccept の組み合わせでも同じ結果が達成されるので、NetRegister を使用するほうが簡単であることがわかります。
この例は、2 つのネットワーク・コンピューター間で簡単なトーク・プログラムを設定する方法を示したものです。 このプログラムは、ピアツーピア環境における 2 つのマシン間の対話を示しています。
KNOWLEDGEBASE NetTalk;
CONSTANTS menuList IS { '~File', 'e~Xit', '', '~Host', '~Open', '', '~Help', '~About', '' }: LIST OF STRING; MsgUserChar IS $MsgUser; MsgRemoteChar IS $MsgUser + 1; MsgTalkClose IS $MsgUser + 2;
ROUTINES
EVENT TalkMainEvent; FUNCTION CreateTalkWindow( VAL host: NETCONNECTION ) : WINDOW; PROCEDURE NetTalkMain;
PRIVATE TYPES TALK_RECORD IS RECORD xLen: INTEGER; -- ウィンドウの幅 (文字数) yLen: INTEGER; -- ウィンドウの高さ (文字数) whdlMe: WINDOW; -- ローカル入力が表示される ウィンドウ whdlYou: WINDOW; -- リモート入力が表示される ウィンドウ host: NETCONNECTION; -- ホストの扱い END;
PANNEL_DATA IS RECORD whdlParent: WINDOW; curX: INTEGER; -- ウィンドウ上のカーソルの X 軸位置 curY: INTEGER; -- ウィンドウ上のカーソルの Y 軸位置 lines: LIST OF STRING; -- 編集中のすべての行のリスト END;
ROUTINES
NETCONNECTION EVENT TalkConnectEvent(REF whdl: WINDOW )IS VARIABLES result : INTEGER;
ACTIONS WHEN $Event IS $MsgNetConnect THEN -- トーク・ウィンドウを作成。 -- このトーク・セッションをサービスする接続を作成 result := NetConnect( $Handle ); IF result < 1 THEN WinMessageBox(whdl,'Error',$MBOk + $MBIconError, 'Connection failed ERROR ' & result ); Exit( 0 ); END; whdl := CreateTalkWindow( $handle ); IF whdl = $UNKNOWN THEN WinMessageBox(whdl,'Error',$MBOk + $MBIconError, 'Window creation failed' ); NetClose( $Handle ); Exit( 0 ); END; ELSWHEN MsgRemoteChar THEN -- リモート・マシンからトーク・ウィンドウに 文字を転送 SendMessage( whdl, MsgRemoteChar, $KeyCode ); ELSWHEN MsgTalkClose THEN NetClose( $Handle ); ELSWHEN $MsgNetClose THEN -- リモート・マシンでウィンドウがクローズした時に ここで終結処理 SendMessage( whdl, $MsgClose ); NetClose( $Handle ); END; END;
EVENT TalkMainEvent IS VARIABLES host : NETCONNECTION; hostName : STRING; result : INTEGER;
ACTIONS WHEN $Event IS $MsgCreate THEN WinSetMenuBar( $Handle, menuList ); ELSWHEN $MsgMenu THEN WHEN $MenuSelection IS 101 THEN SendMessage( $Handle, $MsgClose ); ELSWHEN 201 THEN WinEditField($Desktop, hostName, 0, 0, 40, 'Enter host name', BitOr($WinTitle, $WinBorder, $WinAutoPos ) ); -- ホスト名へのトーク接続を作成 result := NetConnect( host, hostName, 'Talk' ); IF result <> 1 THEN WinMessageBox($Handle, 'Error', $MBOk + $MBIconError, 'Connection failed ERROR ' & result ); END; END; END; END; EVENT TalkPannelEvent( REF pannelData: PANNEL_DATA ) IS ACTIONS WHEN $Event IS $MsgCreate THEN pannelData.curX := 1; pannelData.curY := 1; ListInsert( pannelData.lines, '' ); ELSWHEN $MsgPaint THEN -- ウィンドウを消去して、内容を再表示 WinSetFont($Handle, 'System Monospaced', 10, 0 ); WinClear($Handle ); WinWriteLn($Handle, pannelData.lines ); ELSWHEN $MsgChar THEN -- The parent window processes all characters entered SendMessage(pannelData.whdlParent, $MsgChar, $KeyCode ); ELSWHEN MsgUserChar THEN WHEN $KeyCode IS $KeyReturn THEN -- Enter キーは改行です。 pannelData.curX := 1; pannelData.curY := pannelData.curY + 1; ListInsert(pannelData.lines, '' ); ELSE -- 現在行に文字を追加して、それを表示 WinSetFont($Handle, 'System Monospaced', 10, 0 ); WinGotoXY($Handle, pannelData.curX, pannelData.curY ); WinWrite($Handle, Char( $KeyCode ) ); pannelData.curX := pannelData.curX + 1; pannelData.lines[ $CURRENT ] := StrInsert(pannelData.lines [ $CURRENT ], Char( $KeyCode ), 1000 ); END; END; END;
EVENT TalkEvent( REF talkData: TALK_RECORD ) IS VARIABLES pannel : PANNEL_DATA; yLen : INTEGER;
ACTIONS WHEN $Event IS $MsgCreate THEN -- ローカル文字用とリモート文字用に 2 つの表示 パネルを作成し、親中で渡す pannel.whdlParent := $Handle; yLen := talkData.yLen / 2; WinCreate($Handle, talkData.whdlMe, TalkPannelEvent{ pannel }, 0, 0, talkData.xLen, yLen, '', $WinField ); yLen := talkData.yLen - yLen; WinCreate($Handle, talkData.whdlYou, TalkPannelEvent{ pannel }, 0, yLen + 1, talkData.xLen, yLen,'', $WinField ); ELSWHEN $MsgDestroy THEN PostMessage( talkData.host, MsgTalkClose ); ELSWHEN $MsgSize THEN -- ウィンドウがサイズ変更された時にウィンドウに 合うようにパネルの位置とサイズを設定 talkData.xLen := $EventParm( 1, INTEGER ); talkData.yLen := $EventParm( 2, INTEGER ); yLen := talkData.yLen / 2; SendMessage(talkData.whdlMe,$MsgSetSize talkData.xLen, yLen); yLen := talkData.yLen - yLen; SendMessage(talkData.whdlYou,$MsgSetSize, talkData.xLen,yLen ); SendMessage(talkData.whdlYou,$MsgMove,1, yLen + 1 ); ELSWHEN $MsgChar THEN -- 表示用にローカル文字を上部パネルに送る SendMessage(talkData.whdlMe, MsgUserChar, $KeyCode ); -- また表示用に文字をリモート・ホストにも送る PostMessage(talkData.host, MsgRemoteChar, $KeyCode ); ELSWHEN MsgRemoteChar THEN -- 表示用にリモート文字を下部パネルに送る SendMessage(talkData.whdlYou, MsgUserChar, $KeyCode ); ELSWHEN $MsgPaint THEN WinClear( $Handle ); END; END;
FUNCTION CreateTalkWindow( VAL host : NETCONNECTION ) : WINDOW IS VARIABLES whdlNetTalk: WINDOW; talkData: TALK_RECORD; result: INTEGER;
ACTIONS talkData.host := host; result := WinCreate($Desktop, whdlNetTalk, TalkEvent{talkData}, 0, 0, 0, 0, NetGetHostName(host), BitOr($WinBorder, WinTitle, $WinResize, $WinSysMenu, $WinAutoSize, $WinAutoPos, $WinTaskList)); IF result < 1 THEN WinMessageBox($Desktop, 'Error', $MBOk + $MBIconError, 'Cannot create talk main window. Error: '&result ); END; EXIT( whdlNetTalk ); END;
PROCEDURE NetTalkMain IS VARIABLES whdlNetTalk: WINDOW; result: INTEGER;
ACTIONS result := WinCreate($Desktop, whdlNetTalk, TalkMainEvent, 0, 0, 40, 0, 'Network talk program', BitOr($WinBorder, $WinTitle, $WinResize, $WinSysMenu, $WinMenu, $WinTaskList)); IF result < 1 THEN WinMessageBox($Desktop, 'Error', $MBOk + $MBIconError, 'Cannot create talk main window. Error: ' &result ); END; NetRegister( TalkConnectEvent, 'Talk' ); WinWait( whdlNetTalk ); END;
Tivoli Service Desk 6.0 Developer's Toolkit Script プログラミングの手引き