連載
» 2007年09月14日 00時00分 公開

Symbian OS開発の勘所(8):クライアントサーバという究極の設計思想 (2/4)

[大久保 潤 管理工学研究所,@IT MONOist]

利用者から見たクライアントサーバ

 では、サーバは利用者側からどのように見えるのでしょうか。ファイルサーバを例に説明を進めます。

 ファイルサーバは、ファイルおよびその格納先であるフォルダを操作する機能一式を提供するものです。多くのOSにおけるファイルシステムと同様、Symbian OSでも以下の2つの観点でAPIを整理しています。


  1. フォルダ、またそこに含まれるファイルを操作する
  2. ファイルを開いて内容を操作する

 1に関する操作はRFsというクラスに集約されています。Rから名前が始まる場合、第3回のクラスの命名規則で説明したとおり、ほかのエンティティ(カーネルや他プロセス)が所有するリソースを参照するためのクラスとなります。確かにファイルサーバは他プロセスであるので、そこに処理を委託するためのクラスにふさわしい名前です。ではこのRFsクラスはどのようにファイルサーバと通信をしているのでしょうか。クラス定義を眺めてみましょう。

RFsの概要 図2 RFsの概要

 MkDir()やRmdir()、Rename()やDelete()など、名前から機能が即座に想像できるAPIが並んでいるのに交ざって、Connect()という見慣れないメンバ関数がいます。これこそがファイルサーバに接続するための、クライアントサーバに特徴的なAPIです。ただし名前はConnect()に決まっているわけではありません。後出のRFileクラスではOpen()という名称を用いています。

 RFsを使ってファイルを移動するコードのサンプルを見てみましょう。

RFsを用いたファイル移動処理 図3 RFsを用いたファイル移動処理

 前処理のセクションではConnect()関数を発行しています。この関数の延長でファイルサーバに対して接続が行われ、以後要求を発行することが可能になります。サーバに対して通信をうんぬんというと非常に厄介なもののような気がしますが、実際には特定のAPIを決まり事として呼び出しておく以外にコストが発生することはありません。なお、CleanupClosePushL()と、それに対応する後処理のCleanupStack::PopAndDestroy()は、第4回で解説しているクリーンナップスタック(CleanupStack)というメモリ(リソース)管理フレームワークの機能です。これにより例外フリーな後始末(Connect()で開始された接続の切断)が保証されます。

 処理実体である部分にもクドクドとコードが書かれていますが、よく見れば最初の2行は文字列の定数宣言をするためのコードです(注2)。またUser::LeaveIfError()は、負の値を受け取ったときに、それを値としてリーブを発生させるものです。というわけで、処理実体はRFsのAPI呼び出しと、そのサポートコードから構成される形になっています。

 まとめると、ファイルサーバに処理を要求するというと大事のように聞こえますが、実のところ、

  1. 最初に接続APIを決まり事として呼んでおく
  2. 最後に切断を必ず行う

さえ守っておけば、後はクラスラッピングされたAPI呼び出しにすぎません。OO(オブジェクト指向)環境においてはクライアントサーバといえども適切にラッピングされ、ただのAPI呼び出しと見分けがつかない形で提供されるのです。Symbian OSでは、このラッピング用クラスとそれが提供するAPIのことを併せて、クライアントサイドAPIと呼称します。そしてこのクライアントサイドAPIを用意する義務があるのは、当然ですがサーバの提供者です。クライアントのプログラムは、あくまでクライアントサイドAPIを使うだけなのです。

 なお上記のサンプルコードが仰々しく見えてしまうのは、第2回から第7回までで解説したSymbian OSのイディオムをすべて使用しているからですが、これはつまるところ慣れの問題です。ロバストかつモバイル向けのコードが必要なのであれば、いずれ必ず見慣れると思ってください(注3)。

 ただし今回は特別に、まだSymbian OSのイディオムに移行できていないという人のために、例外処理を無視した、不完全なバージョンのサンプルを付記しておきます。

RFsを用いたファイル移動処理 図4 RFsを用いたファイル移動処理(例外非対応版)

 図3のコードと見比べてみてください。

※注2:
第5回の文字列関連の回で解説して……いませんでした。Symbian OSでは文字列定数を宣言する際には「_LIT()」というマクロを用いて「_LIT( 定数シンボル, リテラル )」のように宣言をし、TLitC型の定数を得ます。上記の例ではKPath1、KPath2がTLitC型です。


※注3:
しかも実際のGUIプログラム環境では、GUIフレームワークがRFsオブジェクトを常に抱えていて、かつEnv()->FsSession()で借りることができるため、自力でConnect()を発行したり、それをクリーンナップスタックに積むことはまずありません。


Copyright © ITmedia, Inc. All Rights Reserved.