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