ACE日志服务器初始版本
server端实现代码
Logging_server.h
#include "ace/FILE_IO.h"
#include "ace/SOCK_Acceptor.h"
class ACE_SOCK_Stream;
class Logging_Server
{
public:
//日志服务初始化和事件循环的模板方法
virtual int run(int argc, char *argv[]);
protected:
virtual int open(u_short logger_port = 0);
//等待多个事件发生
virtual int wait_foro_multiple_events() { return 0; }
//接受一个或多个来自客户的连接,定义为纯虚方法保证子类会实现它
virtual int handle_connections() = 0;
//接受来自客户端的日志记录,并将其写入日志文件
virtual int handle_data(ACE_SOCK_Stream * = 0) = 0;
int make_log_file(ACE_FILE_IO &, ACE_SOCK_Stream * = 0);
virtual ~Logging_Server() {
acceptor_.close();
}
ACE_SOCK_Acceptor &acceptor() {
return acceptor_;
}
private:
ACE_SOCK_Acceptor acceptor_;
};
Logging_server.cpp
#include"ace/FILE_Addr.h"
#include"ace/FILE_Connector.h"
#include"ace/FILE_IO.h"
#include"ace/SOCK_Stream.h"
#include"ace/INET_Addr.h"
#include"Logging_Server.h"
//run()模板方法中所有方法都可以被子类重写
int Logging_Server::run(int argc, char *argv[])
{
if (open(argc > 1 ? atoi(argv[1]) : 0) == -1)
return -1;
for (;;) {
if (wait_foro_multiple_events() == -1)return -1;
if (handle_connections() == -1)return -1;
if (handle_data() == -1)return -1;
}
return 0;
}
//用来初始化“服务器的地址”和“Logging_server的接受者端点”,以被动地在一个指定端口号上监听
int Logging_Server::open(u_short logger_port)
{
ACE::set_handle_limit();
ACE_INET_Addr server_addr;
int result;
if (logger_port != 0)
result = server_addr.set(logger_port, (ACE_UINT32)INADDR_ANY);
else
result = server_addr.set("ace_logger", (ACE_UINT32)INADDR_ANY);
if (result == -1)
return -1;
return acceptor_.open(server_addr, 1);
}
int Logging_Server::make_log_file(ACE_FILE_IO &logging_file, ACE_SOCK_Stream *logging_peer)
{
char filename[HOST_NAME_MAX + sizeof(".log")];
if (logging_peer != 0)
{
ACE_INET_Addr logging_peer_addr;
logging_peer->get_remote_addr(logging_peer_addr);
logging_peer_addr.get_host_name(filename, HOST_NAME_MAX);
strcat(filename, ".log");
}
else
{
strcpy(filename, "logging_server.log");
}
ACE_FILE_Connector connector;
return connector.connect(logging_file,ACE_FILE_Addr(filename),0,
ACE_Addr::sap_any,0,O_RDWR|O_CREAT|O_APPEND,ACE_DEFAULT_FILE_PERMS);
}
Logging_Handler类对I/O和日志记录的处理工作进行了封装
Logging_Handler.h
#include"ace/FILE_IO.h"
#include"ace/SOCK_Stream.h"
class ACE_Message_Block;
class Logging_Handler
{
protected:
ACE_FILE_IO &log_file_;
ACE_SOCK_Stream logging_peer_;
public:
Logging_Handler(ACE_FILE_IO &log_file) :log_file_(log_file) {}
Logging_Handler(ACE_FILE_IO &log_file,ACE_HANDLE handle) :log_file_(log_file)
{
logging_peer_.set_handle(handle);
}
Logging_Handler(ACE_FILE_IO &log_file, const ACE_SOCK_Stream &logging_peer)
:log_file_(log_file), logging_peer_(logging_peer) {}
int close() { return logging_peer_.close(); }
int recv_log_record(ACE_Message_Block *&mblk);
int write_log_record(ACE_Message_Block *&mblk);
int log_record();
ACE_SOCK_STREAM &peer() { return logging_peer_; }
};
Logging_Handler.cpp
#include"Logging_Handler.h"
#include"ace/Message_Block.h"
#include"ace/CDR_Base.h"
#include"ace/CDR_Stream.h"
#include"ace/Log_Record.h"
#include<iostream>
using namespace std;
int Logging_Handler::recv_log_record(ACE_Message_Block *&mblk)
{
//分配一个新的ACE_Message_Block,用来保存Logging_peer_的主机名
ACE_INET_Addr peer_addr;
logging_peer_.get_remote_addr(peer_addr);
mblk = new ACE_Message_Block(NI_MAXHOST + 1);
peer_addr.get_host_name(mblk->wr_ptr(), NI_MAXHOST );
mblk->wr_ptr(strlen(mblk->wr_ptr() + 1));
//创建ACE_Message_Block用来保存日志记录,
ACE_Message_Block *payload = new ACE_Message_Block(ACE_DEFAULT_CDR_BUFSIZE);
//CDR能够对可移植数据进行解编,但解编数据必须始于“按8字节对齐”的数据边界,调用mb_align()强行
//保证数据正确对齐,对齐操作会加入无用的字节
ACE_CDR::mb_align(payload);
//数据头长度为8字节,成功接收到数据头后payload的写指针会前进,以反映消息块增加了8个字节的长度
if (logging_peer_.recv_n(payload->wr_ptr(), 8) == 8) {
payload->wr_ptr(8);
//创建一个CDR对象,用来解编数据头,CDR对象复制这个数据头避免对payload作任何改动
ACE_InputCDR cdr(payload);
//字节顺序标志类型为ACE_CDR::Boolean,所以不管客户的字节顺序如何都可以被提取出来,然后
//根据指定的字节顺序确定CDR流的字节顺序,提取不确定长度的日志记录payload的长度
ACE_CDR::Boolean byte_order;
cdr >> ACE_InputCDR::to_boolean(byte_order);
cdr.reset_byte_order(byte_order);
ACE_CDR::ULong length;
cdr >> length;
//调整payload的长度来容纳整个记录,紧接着数据头
payload->size(length + 8 + ACE_CDR::MAX_ALIGNMENT);
//将日志记录的余下部分添加到payload消息块中,如果顺利则在payload中更新写指针,以反映数据的增加
//通过“连接字段”将payload链接到mblk,然后返回日志记录的长度
if (logging_peer_.recv_n(payload->wr_ptr(), length) > 0) {
payload->wr_ptr(length);
mblk->cont(payload);
return length;
}
}
//出错情况释放内存
payload->release();
mblk->release();
payload = mblk = 0;
return -1;
}
int Logging_Handler::write_log_record(ACE_Message_Block *&mblk)
{
//对方主机名位于mblk中,日志记录位于mblk的“链接链”中,用send_n方法来写所有“通过cont()指针链接起来”的消息块
if (log_file_.send_n(mblk) == -1) return - 1;
//调试模式下,构造一个CDR流并将内容输出到cerr。
//if (ACE::debug()) {
if (1) {
ACE_InputCDR cdr(mblk->cont());
ACE_CDR::Boolean byte_order;
ACE_CDR::ULong length;
cdr >> ACE_InputCDR::to_boolean(byte_order);
cdr.reset_byte_order(byte_order);
cdr >> length;
ACE_Log_Record log_record;
cdr >> log_record;
log_record.print(mblk->rd_ptr(), 1, cerr);
}
return mblk->total_length();
}
int Logging_Handler::log_record()
{
ACE_Message_Block *mblk = 0;
if (recv_log_record(mblk) == -1) {
return -1;
}
else
{
int result = write_log_record(mblk);
mblk->release();
return result == -1 ? -1 : 0;
}
}
Iterative_Logging_Server.h
#include"ace/FILE_IO.h"
#include"ace/INET_Addr.h"
#include"ace/Log_Msg.h"
#include"Logging_Server.h"
#include"Logging_Handler.h"
class Iterative_Logging_Server :public Logging_Server
{
protected:
ACE_FILE_IO log_file_;
Logging_Handler logging_handler_;
public:
Iterative_Logging_Server() :logging_handler_(log_file_) {}
Logging_Handler &logging_handler() {
return logging_handler_;
}
virtual~Iterative_Logging_Server() {
log_file_.close();
}
protected:
//其它方法
virtual int open(u_short logger_port) {
if (make_log_file(log_file_) == -1)
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "make_log_file()"), -1);
return Logging_Server::open(logger_port);
}
virtual int handle_connections() {
ACE_INET_Addr logging_peer_addr;
if (acceptor().accept(logging_handler_.peer(), &logging_peer_addr) == -1)
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "accept()"), -1);
ACE_DEBUG((LM_DEBUG, "Accept connection from %s\n", logging_peer_addr.get_host_name()));
return 0;
}
virtual int handle_data(ACE_SOCK_Stream *) {
while (logging_handler_.log_record() != -1)
continue;
logging_handler_.close();
return 0;
}
};
Iterative_Logging_Server.cpp
#include "ace/Log_Msg.h"
#include "Interative_Logging_Server.h"
int main(int argc, char *argv[])
{
Iterative_Logging_Server server;
if (server.run(argc, argv) == -1)
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "server.run()"), 1);
return 0;
}
Client端实现代码
Logging_Client.h
#include"ace/OS.h"
#include"ace/CDR_Stream.h"
#include"ace/INET_Addr.h"
#include"ace/SOCK_Connector.h"
#include"ace/SOCK_Stream.h"
#include"ace/Log_Record.h"
#include"ace/Stream.h"
#include<string>
class Logging_Client {
public:
//在已连接的ACE_SOCK_Stream上传输ACE_Log_Record
int send(const ACE_Log_Record &log_record);
//返回ACE_SOCK_Stram实例的引用
ACE_SOCK_Stream &peer() { return logging_peer_; }
~Logging_Client() { logging_peer_.close(); }
private:
ACE_SOCK_Stream logging_peer_;
};
Logging_Client.cpp
#include"Logging_Client.h"
#include<iostream>
using namespace std;
int Logging_Client::send(const ACE_Log_Record &log_record)
{
//为ACE_Log_Record分配足够的空间,将log_record内容插入到CDR流中,并得到流的字节数
const size_t max_payload_size =
4 //type()
+ 8 //timestamp
+ 4//process id
+ 4//data length
+ ACE_MAXLOGMSGLEN//data
+ ACE_CDR::MAX_ALIGNMENT;//padding
ACE_OutputCDR payload(max_payload_size);
payload << log_record;
ACE_CDR::ULong length = payload.total_length();
//创建一个“采用CDR编码”的数据头,这样接收者就可以确定“接收到的CDR流”的字节顺序和大小
ACE_OutputCDR header(ACE_CDR::MAX_ALIGNMENT + 8);
header << ACE_OutputCDR::from_boolean(ACE_CDR_BYTE_ORDER);
header << ACE_CDR::ULong(length);
iovec iov[2];
iov[0].iov_base = header.begin()->rd_ptr();
iov[0].iov_len = 8;
iov[1].iov_base = payload.begin()->rd_ptr();
iov[1].iov_len = length;
return logging_peer_.sendv_n(iov, 2);
}
int main(int argc, char *argv[])
{
//初始化网络节点,并让日志服务器在这个节点上被动侦听,以接受连接
u_short logger_port = argc > 1 ? atoi(argv[1]) : 0;
const char*logger_host = argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST;
int result;
ACE_INET_Addr server_addr;
if (logger_port != 0)
result = server_addr.set(logger_port, logger_host);
else
{
result = server_addr.set("ace_logger", logger_host);
}
if (result == -1)
ACE_ERROR_RETURN((LM_ERROR, "lookup%s,%p\n", logger_port == 0 ? "ace_logger" : argv[1], logger_host), 1);
ACE_SOCK_Connector connector;
Logging_Client logging_client;
//利用已经初始化的ACE_INET_Addr,尝试连接日志服务器
if (connector.connect(logging_client.peer(), server_addr) < 0)
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "connect()"), 1);
//循环连续从标准输入设备读取缓冲数据,并将其转发到日志服务器
cin.width(ACE_Log_Record::MAXLOGMSGLEN);
for (;;) {
std::string user_input;
getline(cin, user_input, '\n');
if (!cin || cin.eof())break;
ACE_Time_Value now(ACE_OS::gettimeofday());
ACE_Log_Record log_record(LM_INFO, now, ACE_OS::getpid());
log_record.msg_data(user_input.c_str());
if (logging_client.send(log_record) == -1)
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "logging_client.send()"), 1);
}
return 0;
}