网络编程 卷一学习(3)

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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值