ACE Tutorial 002
Creating a Better Server


続いて Logging_Handler のコードである。


// $Id$

#ifndef LOGGING_HANDLER_H
#define LOGGING_HANDLER_H

#include "ace/INET_Addr.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "ace/SOCK_Stream.h"
#include "ace/Reactor.h"


/*
  さて、アクセプタはテンプレートにより作成するが、このままではそれに渡すリアクタが無い。
  ここでは簡単にグローバルポインタを利用することにする。
  (後程、リアクタを取る方法について講釈する)
*/

extern ACE_Reactor *g_reactor;


/*
  ここで ACE_Event_Handler の代わりに ACE_Svc_Handler を利用する。
  この重要な理由は、(Svc_Handlerが)SOCK_Stream の扱いやリアクタとのやりとりを知っているからである。
  テンプレートに与える二つ目のパラメータについては、後のサーバで説明する。
  今のところはおまじないとしてそのまま使ってほしい。
*/

class Logging_Handler : public ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH>
{
public:

  
  /*
    クライアントから新しいコネクションが来ると、Acceptor は open() を呼び出す。
  */

  virtual int open (void *)
  {
    ACE_INET_Addr addr;

    
    /*
      接続したクライアントのアドレスを知るために(基底クラスの) peer() メソッドを呼ぶ。
      このメソッドが失敗するのは接続が落ちた時くらいだと思うが、お目にかかったことはない。
   */

    if (this->peer ().get_remote_addr (addr) == -1)
      return -1;

    
    /*
      Acceptor はリアクタへの登録を行ってくれないので、自分でやる。
      これがグローバルポインタを取っておいた理由である。
      クライアントから要求があった時に handle_input() が呼ばれるように READ_MASK を渡すのを忘れるな。
    */

    if (g_reactor->register_handler (this,
                                     ACE_Event_Handler::READ_MASK) == -1)
      ACE_ERROR_RETURN ((LM_ERROR,
                         "(%P|%t) can't register with reactor\n"),
                        -1);

    
    /*
      これが新しい項目である。
      ここではタイマイベントを設定している。
      はじめの2秒で一度イベントが起こり、その後は3秒間隔で発生する。
      今回は単に利用法を説明するためなので、具体的な意味はない。
   */

    else if (g_reactor->schedule_timer (this,
                                        0,
                                        ACE_Time_Value (2),
                                        ACE_Time_Value (3)) == -1)
      ACE_ERROR_RETURN ((LM_ERROR,
                         "can'(%P|%t) t register with reactor\n"),
                        -1);

    ACE_DEBUG ((LM_DEBUG,
                "(%P|%t) connected with %s\n",
                addr.get_host_name ()));

    return 0;
  }

  
  /*
    これはスタイルや好みの問題である。
    デストラクタに全てを詰め込む代わりに、ここへコードを記述して、オブジェクト削除時に呼ぶようにする。
  */

  virtual void destroy (void)
  {
    /* リアクタから登録を抹消する。 */
    g_reactor->remove_handler
      (this,
       ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL);

    /* open() で設定されたタイマを解除する。 */
    g_reactor->cancel_timer (this);

    /* クライアントとの接続を閉じる。  */
    this->peer ().close ();

    /* delete によって動的に確保したメモリを解放する。  */
    delete this;
  }

  
  /*
    何か問題があった場合には close() が呼ばれることになる。
    例えば open() メソッドが (エラーとして)-1を返すと acceptor は後始末のために close() を呼び出す。
  */

  virtual int close (u_long flags = 0)
  {
    
    /*
      基底クラスの ACE_Svc_Handler はフラグパラメータを要求する。
      しかし、ここでは利用しないため UNUSED としておく。
      後の handle_input() でも同様のことを行っている。
    */

    ACE_UNUSED_ARG (flags);

    
    /*
      後始末して自身も消す。
      */

    this->destroy ();
    return 0;
  }

protected:

  /* チュートリアル1と同様に応答する。 */
  virtual int handle_input (ACE_HANDLE)
  {
    char buf[128];
    ACE_OS::memset (buf, 0, sizeof (buf));

    switch (this->peer ().recv (buf,
                                sizeof buf))
      {
      case -1:
        ACE_ERROR_RETURN ((LM_ERROR,
                           "(%P|%t) %p bad read\n",
                           "client logger"),
                          -1);
      case 0:
        ACE_ERROR_RETURN ((LM_ERROR,
                           "(%P|%t) closing log daemon (fd = %d)\n",
                           this->get_handle ()),
                          -1);
      default:
        ACE_DEBUG ((LM_DEBUG,
                    "(%P|%t) from client: %s",
                    buf));
      }

    return 0;
  }

  
  /*
    タイマの時刻が来るたびに handle_timeout() が呼ばれる。
    ここの arg に渡されるのは、schedule_timer() の呼び出しで this の次(2番目)に指定した値である。
    渡す値は void* にキャストできればなんでもよい。
  */

  virtual int handle_timeout (const ACE_Time_Value &tv,
                              const void *arg)
  {
    ACE_UNUSED_ARG(tv);
    ACE_UNUSED_ARG(arg);
    ACE_DEBUG ((LM_DEBUG,
                "(%P|%t) handling timeout from this = %u\n",
                this));
    return 0;
  }

  
  /*
    handle_input() や handle_timer() が -1 を返したら後始末をする。
    */

  virtual int handle_close (ACE_HANDLE,
                            ACE_Reactor_Mask)
  {
    this->destroy ();
    return 0;
  }
};

#endif /* LOGGING_HANDLER_H */


[インデックスへ] [次へ進む]