用ACE静态服务配置实现简单的Echo服务
Stone Jiang (HuiHoo
ace)
本例完善了AGP中的示例
用ACE写静态服务配置与写动态服务配置一样简单.本例实际了一个简单的Echo服务.还包含了如何从ini文件中读取服务配置
ACE静态服务配置演示
示例说明
完善了AGP中19章的例子
演示了如何用ACE实现静态服务配置
项目文件
HA_Status.h/cpp 服务接口程序
ClientHandler.h/cpp 事件处理器
svc_conf.static 静态服务配置文件
status.ini
服务配置文件,服务侦听的端口放在这里面的
调试命令行参数
-f svc_conf.static -d
详细实现代码
main.cpp
//@file: main.cpp
// 静态服务配置主函数
//@author: StoneJiang<2005119@gmail.com>
//@version: 0.1.0
#include "ace/os.h"
#include "ace/Log_Msg.h"
#include "ace/Service_Config.h"
#include "ace/Reactor.h"
int ACE_TMAIN(int argc, ACE_TCHAR* argv[])
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("启动主函数\n")));
ACE_STATIC_SVC_REGISTER (HA_Status_Descriptor);
ACE_Service_Config::open (argc,
argv,
ACE_DEFAULT_LOGGER_KEY,
0);
ACE_Reactor::instance ()->run_reactor_event_loop ();
return 0;
}
HA_Status.h
//@file: HA_Status.h
// 服务接口类
#ifndef HA_STATUS_H
#define HA_STATUS_H
#include "ace/Service_Object.h"
#include "ace/INET_Addr.h"
#include "ace/Acceptor.h"
#include "ace/SOCK_Acceptor.h"
#include "ClientHandler.h"
class HA_Status :public ACE_Service_Object
{
public:
virtual int init (int argc, ACE_TCHAR *argv[]);
virtual int fini (void);
virtual int info (ACE_TCHAR **str, size_t len) const;
private:
ACE_Acceptor<ClientHandler, ACE_SOCK_ACCEPTOR> acceptor_;
ACE_INET_Addr listen_addr_;
};
#endif HA_Status.cpp
//@file: HA_Status.cpp
// 服务接口类的实现
#include "HA_Status.h"
#include "ace/service_config.h"
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_string.h"
#include "ace/Get_Opt.h"
#include "ace/Configuration.h"
#include "ace/Configuration_Import_Export.h"
int
HA_Status::init (int argc, ACE_TCHAR *argv[])
{
static const ACE_TCHAR options[] = ACE_TEXT (":f:");
ACE_Get_Opt cmd_opts (argc, argv, options, 0);
if (cmd_opts.long_option
(ACE_TEXT ("config"), 'f', ACE_Get_Opt::ARG_REQUIRED) == -1)
return -1;
int option;
ACE_TCHAR config_file[MAXPATHLEN];
ACE_OS::strcpy (config_file, ACE_TEXT ("HAStatus.conf"));
while ((option = cmd_opts ()) != EOF)
switch (option)
{
case 'f':
ACE_OS::strncpy (config_file,
cmd_opts.opt_arg (),
MAXPATHLEN);
break;
case ':':
ACE_ERROR_RETURN
((LM_ERROR, ACE_TEXT ("-%c requires an argument\n"),
cmd_opts.opt_opt ()),
-1);
default:
ACE_ERROR_RETURN
((LM_ERROR, ACE_TEXT ("Parse error.\n")), -1);
}
ACE_Configuration_Heap config;
config.open ();
ACE_Registry_ImpExp config_importer (config);
if (config_importer.import_config (config_file) == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("%p\n"),
config_file),
-1);
ACE_Configuration_Section_Key status_section;
if (config.open_section (config.root_section (),
ACE_TEXT ("HAStatus"),
0,
status_section) == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("Can't open HAStatus section")),
-1);
u_int status_port;
if (config.get_integer_value (status_section,
ACE_TEXT ("ListenPort"),
status_port) == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("HAStatus ListenPort does ")
ACE_TEXT ("not exist\n")),
-1);
this->listen_addr_.set (static_cast<u_short> (status_port));
if (this->acceptor_.open (this->listen_addr_) != 0)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("HAStatus %p\n"),
ACE_TEXT ("accept")),
-1);
ACE_DEBUG((LM_DEBUG,ACE_TEXT("listen port = %d\n"),
listen_addr_.get_port_number()));
return 0;
}
// Listing 1
// Listing 2 code/ch19
int
HA_Status::fini (void)
{
this->acceptor_.close ();
return 0;
}
// Listing 2
// Listing 3 code/ch19
int
HA_Status::info (ACE_TCHAR **str, size_t len) const
{
ACE_TCHAR buf[BUFSIZ];
ACE_OS::sprintf (buf, ACE_TEXT ("HAStatus listening on port %hu\n"),
this->listen_addr_.get_port_number ());
if (*str == 0)
*str = ace::strnew (buf);
else
ACE_OS::strncpy (*str, buf, len);
return static_cast<int> (ACE_OS::strlen (*str));
}
// Listing 3
// Listing 4 code/ch19
ACE_FACTORY_DEFINE (ACE_Local_Service, HA_Status)
ACE_STATIC_SVC_DEFINE (HA_Status_Descriptor,
ACE_TEXT ("HA_Status_Static_Service"),
ACE_SVC_OBJ_T,
&ACE_SVC_NAME (HA_Status),
ACE_Service_Type::DELETE_THIS |
ACE_Service_Type::DELETE_OBJ,
0) // Service not initially active
ACE_STATIC_SVC_REQUIRE (HA_Status_Descriptor) ClientHandler.h
//@file: ClientHandler.h
// 事件类
//@author: AGP
#ifndef CLIENT_HANDLER_H
#define CLIENT_HANDLER_H
#include "ace/SOCK_Stream.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/Service_Object.h"
#include "ace/Svc_Handler.h"
class ClientHandler :
public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
{
typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> BASE_T;
public:
int open(void* = 0);
virtual int handle_input(ACE_HANDLE fd = ACE_INVALID_HANDLE);
virtual int handle_output(ACE_HANDLE fd = ACE_INVALID_HANDLE);
};
#endif
ClientHandler.cpp
//@file: ClientHandler.cpp
// ClientHandler类的实现
#include "ClientHandler.h"
#include "ace/os.h"
#include "ace/Time_Value.h"
#include "ace/Message_Block.h"
int ClientHandler::open(void* p)
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("open\n")));
if (BASE_T::open (p) == -1)
return -1;
ACE_TCHAR peer_name[MAXHOSTNAMELEN];
ACE_INET_Addr peer_addr;
if (this->peer ().get_remote_addr (peer_addr) == 0 &&
peer_addr.addr_to_string (peer_name, MAXHOSTNAMELEN) == 0)
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%P|%t) Connection from %s\n"),
peer_name));
return 0;
}
int ClientHandler::handle_input(ACE_HANDLE fd /**//* = ACE_INVALID_HANDLE */)
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("handle_input\n")));
const size_t INPUT_SIZE = 4096;
char buffer[INPUT_SIZE];
ssize_t recv_cnt, send_cnt;
recv_cnt = this->peer ().recv (buffer, sizeof(buffer));
if (recv_cnt <= 0)
{
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%P|%t) Connection closed\n")));
return -1;
}
buffer[recv_cnt] = 0;
send_cnt =
this->peer ().send (buffer,
ACE_static_cast (size_t, recv_cnt));
ACE_DEBUG((LM_DEBUG,ACE_TEXT("收到的消息是[%s]\n"),buffer));
if (send_cnt == recv_cnt)
return 0;
if (send_cnt == -1 && ACE_OS::last_error () != EWOULDBLOCK)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("send")),
0);
if (send_cnt == -1)
send_cnt = 0;
ACE_Message_Block *mb;
size_t remaining =
ACE_static_cast (size_t, (recv_cnt - send_cnt));
ACE_NEW_RETURN
(mb, ACE_Message_Block (&buffer[send_cnt], remaining), -1);
int output_off = this->msg_queue ()->is_empty ();
ACE_Time_Value nowait (ACE_OS::gettimeofday ());
if (this->putq (mb, &nowait) == -1)
{
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p; discarding data\n"),
ACE_TEXT ("enqueue failed")));
mb->release ();
return 0;
}
if (output_off)
return this->reactor ()->register_handler
(this, ACE_Event_Handler::WRITE_MASK);
return 0;
}
int ClientHandler::handle_output(ACE_HANDLE fd /**//* = ACE_INVALID_HANDLE */)
{
ACE_Message_Block *mb;
ACE_Time_Value nowait (ACE_OS::gettimeofday ());
while (-1 != this->getq (mb, &nowait))
{
ssize_t send_cnt =
this->peer ().send (mb->rd_ptr (), mb->length ());
if (send_cnt == -1)
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("send")));
else
mb->rd_ptr (ACE_static_cast (size_t, send_cnt));
if (mb->length () > 0)
{
this->ungetq (mb);
break;
}
mb->release ();
}
return (this->msg_queue ()->is_empty ()) ? -1 : 0;
}
特别说明,下面是某网友的问题
我在用ACE中Service-Config框架配置静态服务时,出现下列错误:
error C2146: syntax error : missing ';' before identifier 'ace_svc_desc_Time_Service_Descriptor'
error C2501: 'ACE_Static_Svc_Descriptor' : missing storage-class or type specifiers
出错的地方为:
ACE_STATIC_SVC_DEFINE(Time_Service_Descriptor,
ACE_TEXT("time"), ACE_SVC_OBJ_T,
&ACE_SVC_NAME(TimeService), ACE_Service_Type::DELETE_THIS|ACE_Service_Type::DELETE_OBJ, 1)
问题所在
需要在HA_Status.cpp中包含,这一点是AGP书上未指明的
#include "
ace/service_config.h"