9.その他の IPC(プロセス間通信) 方法
これまでは TCP/IP に関して説明してきたが、ACE は他にもプロセス内およびプロセス間通信のためのラッパークラスを持っている。これらの多くは ACE アクセプターコネクターフレームワークと同様のインターフェースを持ち、同様の利用法が使える。
9.1 UDP/IP によるホスト間 IPC
UDP/IP は TCP と同様に IP によるアドレッシングを行い、各アドレスへのデータはポート番号によって多重化される。アドレッシング情報が似ていることから、UDP でも ACE_INET_Addr クラスをアドレスに利用する。
通信に UDP を利用することを決めたなら、UDP と TCP で異なる以下の3点について考慮してほしい。
- TCP がストリームベースなのに対し、UDP はデータグラムベースである。TCP では 256バイトのデータを三回送った場合、受信側では送信と同じ順序で 768バイトのデータ列が、不定サイズのチャンクに分かれて受け取られる。一方、UDP の場合、ゼロ個から三個までのどれかの個数分だけ、256バイトきっちりのパケットが届く。つまり、UDP はレコード指向の転送を行うのだ。(TCP ではストリームからデータを抽出しなければならない。これをアンマーシャリングと言う。)
- UDP はベストエフォート型の転送を行う。つまり、パケットの到達も、その到達順序も保証しない。上の例で言えば、全部届かないこともあるし、届く順序があべこべになることもある。UDP ではデータをストリームにマーシャル・アンマーシャルする必要がない代わりに、プロトコルやアプリケーションで信頼性を確保しなければならない。
- TCP が1対1の接続に限られているのに対して、UDP では3種類のモードがある。ユニキャスト、ブロードキャスト、マルチキャストである。ユニキャストは TCP と同様に1対1の通信を行う。ブロードキャストは到達範囲内の全ホストに向かってデータを送信する。マルチキャストも複数ホストへ送信するが、こちらはコントロールされた範囲へ送ることでトラフィックへの問題を軽減している。
これから、この三種類のアドレッシングモードを利用したサンプルについて見ていく。どの UDP クラスも ACE リアクタフレームワークに利用できる。また、I/O UDP クラス群は ACE_Svc_Handler クラステンプレートのストリーム引数として渡すことができる。ユニキャストの ACE_SOCK_CODgam クラスはプロアクタフレームワークで利用できるハンドルを持つため、ACE_Asynch_Read_Dgram・ACE_Asynch_Write_Dgram ファクトリクラスでも利用できる。
9.1.1 ユニキャストモード
ユニキャストモードで UDP パケットを送信する例が p.209 に載っている。ここで TCP と違うのは次の2点だ。
- ACE_SOCK_Dgram を簡単に開いて送信ができる。アクセプタもコネクタも必要無い。
- データグラムの送信時に明示的に送信先アドレスを与える必要がある。
上のような違いは UDP 自体の特性に基いている。どのような2点間の通信であっても、そこには接続と呼ばれるような関係は無い。相手のアドレスが分かっていて、そこへ直接送信するだけである。また、上の例では送信後にソケットを閉じてしまっているが、同じソケットをデータグラムの送受信どちらでも利用することができる。さらに別々のアドレスに送信することさえできる。このように、UDP ユニキャストモードは1対1の接続であるが、固定された1対1ではない。
もし書いているアプリケーションが特定のポート番号を利用して送受信するならば、その情報を設定した ACE_INET_Addr オブジェクトを ACE_SOCK_Dgram::open() に渡してやる。特にポートを指定しないのならば ACE_Addr::sap_any を渡せばよい。
データグラムを送信する送信先のアドレスを得るには二つの方法がある。一つ目は TCP で ACE_SOCK_Connector を利用する時と同様に、よく知られたあるいは既知のアドレスとポート番号に対してアクティブに接続する方法である。これはクライアントアプリケーションが、よく知られたサービスにアクセスする時にしばしば用いられる。二つ目は UDP サーバアプリケーションではよく用いられる方法である。これは ACE_SOCK_Dgram へはいくつものピアが送信してこれるため、その送信元を利用する。このタイプのサンプルが p.210 に記載されている。
ACE_SOCK_Dgram::recv() の第三引数に渡したアドレスオブジェクトに、送信元のアドレスが引き渡される。それを利用して受信したデータを送信元へ送り返している。
また、UDP ソケットは ACE_SOCK_Dgram オブジェクトが破棄されるまでは維持されることに注意が必要だ。そうでなければハンドルリークが起こるだろう。
これらの事から、1対1の通信を UDP で行いたい場合、毎回アドレスを指定するのは面倒だし間違いの元だと思った人は正しい。このようなケースに対し、ACE は ACE_SOCK_CODgram クラスによって解決を図っている。これは UDP レベルでは接続を張るわけではないが、内部的に送信先を保持することにより、送信時ごとのアドレス指定を省略することができるのだ。このクラスを使う場合にも、先程と同様にコネクタもアクセプタも使わなくてよい。利用例は p.211 にある。
9.1.2 ブロードキャストモード
ブロードキャストモードでも送信先アドレスは送信のたびに指定する必要がある。IPブロードキャストアドレスはブロードキャスト用に固定されているため、異なるのはポート番号のみとなる。ACE_SOCK_Dgram_Bcast クラスが正しいブロードキャストアドレスを設定してくれるため、プログラマは UDP ポート番号を指定するだけでよい。p.211-212 にサンプルコードが載っている。ACE_SOCK_Dgram_Bcast クラスは ACE_SOCK_Dgram クラスの子クラスであるため、受信操作に関しては先のユニキャストの場合と同様である。
9.1.3 マルチキャストモード
UDP マルチキャストモードは、マルチキャストグループと呼ばれるネットワークノードの集合に関係している。OS が提供しているプロトコルソフトウェアが特別なプロトコルに従ってマルチキャストグループを管理している。OS がアプリケーションの要請に応じてマルチキャストグループを管理する。アプリケーションがグループに加入すると、全ての送信データグラムはマルチキャストグループに属するソケットへ送信される。
各マルチキャストグループは別のIPアドレスを持つ。マルチキャストアドレスはクラスDのもので、クラスA,B,C のどれからも異なる範囲に割り当てられている。アプリケーションはそれに見当ったクラスDアドレスを割り当てられる。
p.212-213 の例はマルチキャストグループへの参加と送信を行っているものである。ACE_SOCK_Dgram_Mcast クラスは ACE_SOCK_Dgram から継承されており、recv() メソッドは継承されたものを用いる。
9.2 ホスト内コミュニケーション
この節で紹介されているクラスはホスト内コミュニケーション専用である。これらはホスト間コミュニケーションに比べてシンプルで高速である。その理由はアドレッシングの単純さと、重厚なプロトコルレイヤやネットワーク遅延の無い通信路を利用できるためだ。ホスト間コミュニケーション機能はホスト内コミュニケーションにも利用でき、その実装によってはホスト内通信用に最適化されている場合もある。中でも TCP/IP ソケットは多数のプラットフォームで利用できる一般的な IPC メカニズムであるので、移植性が重視される場合には劇的にコードが簡略化できる。
IPC メカニズムの選択基準は難しい。選ぶ場合には状況に見当ったベンチマークを行い、アプリケーションでの利用形態においてベストなものを使うべきだ。幸い、ACE の IPC メカニズムはプログラミングインターフェースが似ているため、相互に入れ替えてのテストが容易である。
9.2.1 ファイル
ACE_FILE_IO クラスと ACE_FILE_Connector クラスは、ファイルI/Oをアクセプターコネクターフレームワークのコネクター側として実装している。この時に利用されるアドレスは ACE_FILE_Addr であり、これはファイルのパス名をカプセル化する。
9.2.2 パイプとFIFO
パイプと FIFO は UNIX でのメカニズムである。FIFO は名前付きパイプと呼ばれることもあるが、Windows 名前付きパイプとは異なる。以降に挙げるのは一般的なクラス群である。これらはプラットフォーム依存のため、利用の前にはリファレンスを確認するようにしてほしい。
- ACE_FIFO_Recv、ACE_FIFO_Send、ACE_FIFO_Recv_Msg、ACE_FIFO_Send_Msg:これらは UNIX/POSIX FIFO 上でストリームかつメッセージモードとして動作する。これらにはアドレッシングクラスは無く、利用するデータ転送クラスへ FIFO の名前を渡せばよい。
- ACE_Pipe:これは UNIX/POSIX のパイプを利用する。パイプは UNIX/POSIX 固有の機能のため、windows では TCP/IP のループバックを用いてエミュレートされる。困った時には便利ではあるが、(訳注:おそらく windows と UNIX での)違いに注意しなければならない。パイプのハンドルを取得してローレベルI/Oを使う時には、ACE_OS::read() と ACE_OS::write() が windows ではうまく動かないことになる。これは、windows ではハンドルがソケットハンドルのためである。よって、windows の場合には ACE_OS::recv() と ACE_OS::send() を使わなければならない。また、パイプは名前も他のアドレスも持たないため、アドレッシングクラスは存在しない。
- ACE_SPIPE_Acceptor、ACE_SPIPE_Connector、ACE_SPIPE_Stream、ACE_SPIPE_Addr:これらはアクセプターコネクターフレームワークに従う。このクラス群は windows名前付きパイプあるいは UNIX/POSIX ではストリームパイプを示す。これら二つは同じではないが、プログラム方法は一緒であり、ACE_SPIPE について知っていればよい。
9.2.3 共有メモリストリーム
ACE_MEM_Acceptor、ACE_MEM_Connector、ACE_MEM_Stream、ACE_MEM_Addr は共有メモリストリームに属するクラス群である。これらは共有メモリ(メモリマップドファイルなど)をデータ転送に利用する。この場合、データは実際には転送されず、プロセス間で共有されるメモリ領域に保存されるだけなので、よいパフォーマンスを得られる。
想像したかもしれないが、これらの共有メモリへのアクセス同期はこの方法のトリッキーな点である。これは TCP/IP ソケットで利用したリアクタフレームワークに ACE_MEM_Stream をあてはめることによって同期を取らせることができる。
Index
Top