続いて 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 */