『Cプログラミング診断室』目次次(第11章 奇っ怪な条件 難解な条件)

第11章 奇っ怪な条件

クライアント・サーバモデル


解剖しているプログラムはXのアプリケーションですから、当然クライアント/サーバモデルの 上で動作しているのです。

最近、どこへ行っても、「クライアント/サーバ」という言葉をやたらに聞きます。そういう話 を聞いていて、一番感じるのは、言っている本人がその意味を知っているのかなあということです。 流行語だから、おまじないのように使って、知ったかぶりをするための道具にしか思えないことが 多いのです。

コンピュータショーなどに行くと、きっといっぱい「クライアント/サーバ」という「おまじな い」を聞くでしょう。「うちの製品は、クライアント/サーバモデルに基づいて…」というような 説明を始めるでしょうから、「クライアント/サーバとはどういうことですか?」と聞いてみましょ う。ちゃんと説明できる説明員などまずいないでしょう。きっと、会場に無理矢理来させられた技 術者を連れてきて説明をさせると思います。たぶん、教科書どおりの説明はしてくれるでしょう。 そこで、「クライアント/サーバだったら、どういうメリットがあるのですか?何ができるように なったのですか?」と質問してみましょう。この辺までしっかり答えてくれれば素晴らしい。

そういえば、以前、DTPのショーに行ったとき、ちょっと質問したら、「知り過ぎている。あ なたはどこかの大学の方で、冷やかしにいらしているのですか?」と言われたことがありました。 「恐いオネーサマ」もいるので、質問する前に、相手を見てからにするのも忘れないように。

■召使の使い方■

話がそれてしまいました。Xのアプリケーションは、クライアント/サーバモデルの上で動いて います。要するに、「クライアント」というアプリケーションと、「サーバ」という何かが動いて いるのです。1つの処理をするのに、別者が2つ動いているのですから、正しい処理が行なわれる ためには、両者が連絡しながら連携プレイをとる必要があります。

もっと分かりやすく言えば、「一人でやっていた仕事を二人でやるのが、クライアント(王様) /サーバ(召使)モデル」です。多くの場合、一人でやった方が便利ですよね。召使に何かやらせ るには、命令しなければなりません。というより、いろいろな雑用は、王様がすることが禁じられ ていて、いちいち召使にやらせなければいけない世界なのです。ちょっと町をブラブラしようと思っ ても召使がついてくるし、トイレも一人で行ってはいけないような世界なのです。これが「王様/ 召使モデル」なのです。

こういう世界ですから、2者の間で、いっぱい取り決めがあります。「クライアント/サーバモ デル」でなかった時代には単純だったのに、時代が変わり、「クライアント」と「サーバ」の間で、 「通信」により命令を受け、処理をするようになっりました。この通信がすごい「くせ者」で、X のアプリケーション開発者たちは、よく戸惑っています。

何でも通信すると、通信量が非常に増大して、本来の処理より、無駄な通信と、無駄な通信に基 づいた処理がどんどん増大して、コンピュータは無駄な処理のためにあえぎ、しばしばキーボード やマウスが反応しなくなります。

前置きがとても長くなりましたが、今回のプログラムにも、その片鱗が見えています。それは、 各関数の先頭で、

        event_is_ascii( event )
        event_is_down( event )
        event_action( event )
のようなイベントの種類をチェックする関数やマクロがズラズラと並んでいることです。Xウィン ドでいうイベントとは、「王様/召使いモデル」での、召使が王様に申し上げる「言葉」です。上 の3種の関数やマクロは、この言葉の内容(種別)をチェックしているわけです。不要な発言か、 欲しかった発言かをチェックしているのです。

ここで問題があります。召使が、どうでもよいことをぐちゃぐちゃしゃべったら、うるさくて困 ると思いませんか。必要な時だけしゃべって欲しいものです。上のイベントチェックの並びは、ム ダなものがいっぱい含まれている中から、必要なものを判別している処理です。

■無駄口封じ■

実は、「知らせて欲しいことを召使に教えておき、他のことは無視せよ」とできるのです。この ように書き換えれば、各関数の先頭にあるイベントのチェック部分は不要になります。プログラム が短くすっきりするだけではなく、「無駄口」の時間がなくなり、コンピュータの負荷も下がりま す。

イベントは、王様から召使いに対して、最初に、「伝えるべきことのメモ」を渡すことになって います。そのための関数呼びだしが、

    xv_set( mac_up_canvas,
            WIN_EVENT_PROC, mac_up_event,
            WIN_CONSUME_EVENTS,
                LOC_WINENTER,
                LOC_WINEXIT,
                LOC_MOVE,
                LOC_DRAG,
                KBD_DONE,
                KBD_USE,
                WIN_MOUSE_BUTTONS,
                NULL,
            NULL );
です。WIN_CONSUME_EVENTSに続く行が受けつける(王様に知らせる)イベントの種類です。マウス イベントしか利用しないのだから、WIN_MOUSE_BUTTONS以外の並びは存在するだけ「悪」で、
    xv_set( mac_up_canvas,
            WIN_EVENT_PROC, mac_up_event,
            WIN_CONSUME_EVENTS,
                WIN_MOUSE_BUTTONS,
                NULL,
            NULL );
のように直すべきです。すると、event_is_asciiが不要になります。

■イベントを止めよう■

XViewあるいはMotifのようなGUI(Graphical User Interface)では、あまりイベントを明示的に 使わない方が一般的です。イベントのような低レベルではなく、「ボタンが押されたよ」というよ うな「人間的レベル」に合った機能が提供されています。それは、XViewではノーティファイア、 Motif(あるいはXツールキット)ではコールバックといいます。細かい差はありますが、より上 位レベルのものという点では同じです。

さて、元のプログラムはXViewで書かれていたのですが、「XViewを捨てMotifへ移行という時代 の流れ」に沿い、Motifへ移植してしまいました。そういうことで、改定最終案はMotif版をお見せ します(リスト11−4)。

リスト11−4 修正版(その3)Motifでの実現

     1  void    mac_move_event( w, direction, call_data )
     2    Widget    w;
     3    char      direction;  /* 'u', 'd', 'l', 'r'   */
     4    caddr_t   call_data;
     5  {
     6          int         mac_step_x, mac_step_y;
     7          RECT        rectdisp;
     8          RECT        rectbase;
     9          Window      win_disp;
    10  
    11          mac_step_x = mac_width  / mac_mag;
    12          mac_step_y = mac_height / mac_mag;
    13  
    14          switch( direction ) {
    15          case 'u':       /* up    */
    16                  mac_y -= mac_step_y/2;
    17                  break;
    18          case 'd':       /* down  */
    19                  mac_y += mac_step_y/2;
    20                  break;
    21          case 'l':       /* left  */
    22                  mac_x -= mac_step_x/2;
    23                  break;
    24          case 'r':       /* right */
    25                  mac_x += mac_step_x/2;
    26                  break;
    27          }
    28  
    29          if ( mac_x > xdot - mac_step_x )
    30                  mac_x = xdot - mac_step_x;
    31          if ( mac_x < 0 )
    32                  mac_x = 0;
    33          if ( mac_y > ydot - mac_step_y )
    34                  mac_y = ydot - mac_step_y;
    35          if ( mac_y < 0 )
    36                  mac_y = 0;
    37  
    38          mac_posx = mac_x + mac_step_x/2;
    39          mac_posy = mac_y + mac_step_y/2;
    40          rectdisp.x = 0;
    41          rectdisp.y = 0;
    42          rectdisp.size_x = mac_width;
    43          rectdisp.size_y = mac_height;
    44          rectbase.x = mac_x;
    45          rectbase.y = mac_y;
    46          win_disp = my_canvas_paint_winid( mac_canvas );
    47          mac_cur = OFF;
    48          disp_data( &rectdisp, &rectbase, mac_mag, &mac_point,
    49                     mac_image_ad, mac_image->bytes_per_line, ON );
    50          XPutImage( motif_display, win_disp, mac_paint_gc, mac_image,
    51                     rectdisp.x, rectdisp.y,
    52                     rectdisp.x, rectdisp.y,
    53                     rectdisp.size_x, rectdisp.size_y );
    54  }

リスト11−2とかなり似ているでしょう。しかし、いままでは上下左右の4つの関数がありま したが、完全に1つの関数になっています。共通化された関数が直接呼ばれる便利な状況になって います。さらに重要なことは、イベントに関する条件判定が完全になくなったことです。どの向き かは引数で与えられています。 さらに、使用していない変数 x, y, point1, point2も削除しました。目障りだった余分なキャ ストも取り去りました。かなり「すっきり」したでしょう。

■それでもクライアント・サーバ■

クライアント(ふつうは主人という。王様というのは映画の影響か)/サーバモデルの欠点ばか り挙げてきましたが、利点もあります。2者は別々のソフトになるので、互いに別のコンピュータ で動かすこともできます。複雑な処理は能力の高いコンピュータでやり、グラフィック表示は表示 に優れたディスプレイを持ったコンピュータを使うというような「使い分け」ができることです。

もう1つは、データベースのようなもので、複数のコンピュータ上で動いている多数のプログラ ムから自由に呼ばれるが、必ずデータは一元管理しなければならないものです。かな漢字変換サー バもこの類です。

Xウィンドの表示は、Xサーバが担当しています。したがって、Xサーバが動いているところな らどこにでも表示できます。この機能があることで、ウィンド上のアプリケーション開発がずいぶ ん助かっています。デバッガとアプリケーションの表示をしているディスプレイを別にできなかっ たら、ウィンドベースのソフトウェアのデバッグはまず不可能でしょう。こういうとき、X端末が あると、すごーく便利ですよ。


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第11章 奇っ怪な条件 難解な条件)