2005年08月13日

自己記述型データを名前でアクセスする方法

あなたがクライアント/サーバー型の
アプリケーションをつくる場合、
アプリケーション間で送受信するメッセージの
データ構造はどのように設計し実装していますか?
そんな迷えるあなたに、
自己記述型のデータ構造(Self Describe Data)!
ちょいとかじってみますか。

ひと昔前のプログラムが扱うメッセージのデータ構造は、
データだけを順に連ねたとてもシンプルな構造でした。
このメッセージを送受信するプログラムは、
データ構造を解釈するために、
データ構造をあらわす構造体をデータに被せ、
各項目にアクセスしていました。

このデータ構造はデータ自身から、
その構造を求めることが出来ず、
必ずデータ構造をあらわす入れ物が必要になると同時に、
各項目の並びや長さが厳密に規定されているため、
データ構造の変更に柔軟に対応できませんでした。

最近では、SOAPのXMLやSEMIのSECSといった
データ構造に代表される通り、
データがデータの中身である値と、その構造をあらわす
自己記述型のデータ構造が主流となっています。
今回はこの自己記述型のデータ構造を
実現するサンプルプログラムをDelphiでご紹介します。

サンプルプログラムの作成に当り、
2つのキーとなるクラスを作成しています。
「TDatumNode」はデータ構造内の
1項目(要素)をあらわすオブジェクト、
「TContainerNode」は
「TDatumNode」のオブジェクトや、
「TDatumNode」の派生である
「TContainerNode」のオブジェクトを
複数格納するコンテナオブジェクトとして機能します。
丁度、OSファイルシステムの
「ファイル」と「ディレクトリィ」の概念に相当します。
「ファイル」が「TDatumNode」に、
「ファイル」や「ディレクトリィ」を格納する
「ディレクトリィ」が「TContainerNode」に、
それぞれ対応するイメージだと思ってください。

それでは、お疲れ様です。
じっくりソースを解析し、色々と試して下さい。

全ソースは【続きを読む】をクリック!

尚、サンプルプログラムは
「TContainerNode」オブジェクトのデータを
ストリームに保存したり、読込んだりする
メソッドは実装しておりません。
データ構造内の1項目(要素)をあらわす
「TDatumNode」オブジェクトに、
格納できるデータは便宜上文字型のみとしています。
必要あらば、あなた自身で追加してください。(笑い)

【クラスダイアグラム】

DatumClass.gif

【画面イメージ】

DatumClassTester.gif

関連書籍


Copyright guy@かしらもんじ でぇ〜

続きを読む
posted by guy at 07:22 | 通信編

2005年07月29日

TCP/IPコネクション型ソケットで非同期通信する方法

TCP/IPのコネクション型ソケット(socket)を使い
プログラム同士を効率よく通信させたいのだけど、
処理をブロッキングすることなく通信させるには
どうしたらよいか悩んだことはありませんか?

今回はプログラム同士が
TCP/IP通信を実現するため、
接続、切断、受信、送信完了の
各事象をイベント駆動型で
プログラムに通知し効率よく通信させる
方法をDelphiでご紹介します。

一般的にTCP/IPのサーバタイプは特定の
サービスをクライアントに提供するため、
特定のポート番号でソケットをオープンし、
クライアントからの接続を待ちます。

一方、TCP/IPのクライアントは特定の
サービスをサーバに要求するため、
サービスを提供している相手(サーバ)と
そのサービスを表すポート番号へ、
ソケットを接続しサービスの要求を行います。

サービスの代表的なものに、
ftp、telnetなどは良くご存知かと思います。
もう少し具体的に見ていくと、
サーバ、クライアントの主な処理は次のようになります。

サーバ処理
説明
@サービスの開始
TCP/IPのストリームソケットを作成(socket)し、自分のIPアドレスとサービスを提供するポート番号をバインド(bind)する。
リッスン(listen)を行い、クライアントから接続を待つ。
サンプルプログラムは、終了するまでこのソケットを維持し、クライアントから接続の要求を受付け続ける。
A接続の受理
@のソケットにクライアントから接続要求があるか検査(select)する。
クライアントから接続要求があった場合、接続を受理(accept)する。
接続の受理に成功した場合、データ送受信用に新しいソケットが確保される。
以降のデータ送受信はこのソケットが使用される。
B要求の受信
Aのソケットでクライアントからデータを受信しているか検査(select)する。
受信データがある場合、取得(recv)する。
Cサービスの実行
クライアントの要求データでサーバのサービスを実行し、必要であれば応答データを戻す。
サンプルプログラムは、クライアントから受信したデータをそのままクライアントへ送信する。
D応答の送信
Cの処理でクライアントへ何らかの応答データを送信する場合、Aのソケットでクライアントへデータを送信できるか検査(select)する。
データを送信できる場合、送信(send)する。
E終了処理
全てのソケットを閉じ(closesocket/close)終了する。

クライアント処理
説明
@接続の要求
TCP/IPのストリームソケットを作成(socket)し、相手(サーバ)のIPアドレスとサーバのポート番号を設定し接続要求(connect)を行う。
サーバがクライアントの接続を受理した場合、接続は成功する。
サーバが不在かサーバのサービスが開始されていない場合、接続は失敗する。
A要求の送信
@のソケットでクライアントが要求データを送信できるか検査(select)する。
データを送信できる場合、送信(send)する。
サンプルプログラムは、画面で入力されたテキストを送信する。
B応答の受信
@のソケットでサーバから応答データを受信しているか検査(select)する。
受信データがある場合、取得(recv)する。
サンプルプログラムは、サーバがクライアントのデータをエコーバックするので、クライアントは自分が送信したテキストを受信する。
C終了処理
全てのソケットを閉じ(closesocket/close)終了する。

ここで問題になるのは
クライアントとサーバ間で
実際にやり取りするデータです。
送受信データの終わりはTCP/IP上に
実装されるプログラムの責任で行う必要があります。


送信データ長がウインドサイズを超えるような
データを送受信する場合、
送信側で仮に一回で送信できたとしても、
受信側では何回かに分けて受信することになります。
select関数はソケットに受信データがあるかないか、
送信できる状態であるかないかの情報は取得できても
送受信データがどこで終わっているか判断がつかないのです。

select関数の受信事象をそれぞれ
バラバラのデータと認識したのでは、
とんでもないことになりますね。
(初心者の方はよくやる失敗ですので注意してくださいね。)

サンプルプログラムは
この問題を回避するため、
送受信データの先頭に
ネットワークバイトオーダーのデータ長を付加し、
送信データが全て送信できた時に送信完了イベントを、
受信データを全て受信できた時に
受信イベントが発生するようになっています。

ではでは、早速サンプルプログラムを見ていただきましょう!

全ソースは【続きを読む】をクリック!

プログラムは若干複雑になってますが、
全ソースを公開しますので、
がんばって理解してくださいね。
また役に立ったと思われるあなた、
いつもの良く冷えた"ビ"がつくものおごってくださいね。(笑い)

【画面イメージ】

SocketTester.gif

関連書籍


Copyright guy@かしらもんじ でぇ〜

続きを読む
posted by guy at 07:20 | 通信編

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は1年以上新しい記事の投稿がないブログに表示されております。