文档章节

使用 acl::master_proc 类编写多进程服务器程序

郑树新
 郑树新
发布于 2014/09/03 12:10
字数 1795
阅读 19
收藏 0

      文章《快速创建你的服务器程序》讲述了基于 C 语言版本的 acl 服务器框架下如何开发多进程服务器应用程序。本文则讲述了基于 C++ 语言的 acl_cpp 服务器框架下如何开发多进程服务器应用程序,当然 acl_cpp 下的服务器框架内部也是基于 acl 的服务器框架的。关于基于acl_master 的服务器程序设计原理,请参考 《协作半驻留式服务器程序开发框架》。

      一、类成员函数说明

      master_proc 是一个纯虚类,其中定义的接口需要子类实现,如下:

 

/**
		 * 纯虚函数:当接收到一个客户端连接时调用此函数
		 * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象
		 * 注:该函数返回后,流连接将会被关闭,用户不应主动关闭该流
		 */
		virtual void on_accept(socket_stream* stream) = 0;

     master_proc 类提供了两个函数:

 

/**
		 * 开始运行,调用该函数是指该服务进程是在 acl_master 服务框架
		 * 控制之下运行,一般用于生产机状态
		 * @param argc {int} 从 main 中传递的第一个参数,表示参数个数
		 * @param argv {char**} 从 main 中传递的第二个参数
		 */
		void run_daemon(int argc, char** argv);

		/**
		 * 在单独运行时的处理函数,用户可以调用此函数进行一些必要的调试工作
		 * @param addr {const char*} 服务监听地址
		 * @param conf {const char*} 配置文件全路径
		 * @param count {int} 当该值 > 0 时,则接收的连接次数达到此值且完成
		 *  后,该函数将返回,否则一直循环接收远程连接
		 * @return {bool} 监听是否成功
		 */
		bool run_alone(const char* addr, const char* conf = NULL, int count = 1);

      master_proc 类实例当在生产环境下(由 acl_master 进程统一控制调度),用户需要调用 run_daemon 函数;如果用户在开发过程中需要手工进行调试,则可以调用 run_alone 函数。

      master_proc 的基类 master_base 的几个虚接口如下:

 

/**
		 * 当进程切换用户身份前调用的回调函数,可以在此函数中做一些
		 * 用户身份为 root 的权限操作
		 */
		virtual void proc_pre_jail() {}

		/**
		 * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程
		 * 的权限为普通受限级别
		 */
		virtual void proc_on_init() {}

		/**
		 * 当进程退出前调用的回调函数
		 */
		virtual void proc_on_exit() {}

		// 在 run_alone 状态下运行前,调用此函数初始化一些配置

 

      二、示例

 

// master_proc.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "lib_acl.hpp"

// 字符串类型的配置项
static char *var_cfg_debug_msg;

static acl::master_str_tbl var_conf_str_tab[] = {
	{ "debug_msg", "test_msg", &var_cfg_debug_msg },

	{ 0, 0, 0 }
};

// 布尔类型的配置项
static int  var_cfg_debug_enable;

static acl::master_bool_tbl var_conf_bool_tab[] = {
	{ "debug_enable", 1, &var_cfg_debug_enable },

	{ 0, 0, 0 }
};

// 整数类型的配置项  
static int  var_cfg_io_timeout;

static acl::master_int_tbl var_conf_int_tab[] = {
	{ "io_timeout", 120, &var_cfg_io_timeout, 0, 0 },

	{ 0, 0 , 0 , 0, 0 }
};

static void (*format)(const char*, ...) = acl::log::msg1;

//////////////////////////////////////////////////////////////////////////
using namespace acl;

class master_proc_test : public master_proc
{
public:
	master_proc_test() {}
	~master_proc_test() {}
protected:
	/**
	 * 基类纯虚函数:当接收到一个客户端连接时调用此函数
	 * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象
	 * 注:该函数返回后,流连接将会被关闭,用户不应主动关闭该流
	 */
	virtual void on_accept(socket_stream* stream)
	{
		if (stream->format("hello, you're welcome!\r\n") == -1)
			return;
		while (true)
		{
			if (on_read(stream) == false)
				break;
		}
	}

	bool on_read(socket_stream* stream)
	{
		string buf;
		if (stream->gets(buf) == false)  // 读一行数据
		{
			format("gets error: %s", acl::last_serror());
			return false;
		}
		if (buf == "quit")
		{
			stream->puts("bye!");
			return false;
		}

		if (buf.empty())
		{
			if (stream->write("\r\n") == -1)
			{
				format("write 1 error: %s", acl::last_serror());
				return false;
			}
		}
		else if (stream->write(buf) == -1)
		{
			format("write 2 error: %s, buf(%s), len: %d",
				acl::last_serror(), buf.c_str(), (int) buf.length());
			return false;
		}
		else if (stream->write("\r\n") == -1)
		{
			format("write 3 client error: %s", acl::last_serror());
			return false;
		}
		return true;
	}

	// 基类虚函数:服务进程切换用户身份前调用此函数
	virtual void proc_pre_jail()
	{
		format("proc_pre_jail\r\n");
	}

	// 基类虚函数:服务进程切换用户身份后调用此函数
	virtual void proc_on_init()
	{
		format("proc init\r\n");
	}

	// 基类虚函数:服务进程退出前调用此函数
	virtual void proc_on_exit()
	{
		format("proc exit\r\n");
	}
private:
};
//////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
	master_proc_test mp;

	// 设置配置参数表
	mp.set_cfg_int(var_conf_int_tab);
	mp.set_cfg_int64(NULL);
	mp.set_cfg_str(var_conf_str_tab);
	mp.set_cfg_bool(var_conf_bool_tab);

	// 开始运行

	if (argc >= 2 && strcmp(argv[1], "alone") == 0)
	{
		format = (void (*)(const char*, ...)) printf;
		mp.run_alone("127.0.0.1:8888", NULL, 5);  // 单独运行方式
	}
	else
		mp.run_daemon(argc, argv);  // acl_master 控制模式运行

	return 0;
}

      这是一个简单的提供 echo 行服务的服务器程序,可以支持多个并发连接,而且可以通过配置文件控制所启动的最大进程数、进程空闲时间等控制参数,因为 acl 中的服务器框架都是半驻留的,所以既可以保证运行效率,又能够在空闲释放系统资源。该例子所在目录:acl_cpp/samples/master_proc。

      需要注意的是,master_proc 内部是单例的,即要求该类的对象只能有一个,否则内部自动产生断言。只所以没有采用单例模板来设计单例,主要是为了不对外暴露 acl 库中的接口,使使用 acl_cpp 库的用户不必关心 acl 库的头文件在哪儿。

      三、配置文件及程序安装

      打开 acl_cpp/samples/master_proc/single_echo.cf 配置文件,就其中几个配置参数说明一下:

 

## 由 acl_master 用来控制服务进程池的配置项
# 为 no 表示启用该进程服务,为 yes 表示禁止该服务进程
master_disable = no

# 表示本服务器进程监听 127.0.0.1 的 5002 端口
master_service = 127.0.0.1:5002

# 表示是 TCP 套接口服务类型
master_type = inet

# 进程程序名
master_command = master_proc

# 表示该服务进程池的最大进程数为 2
master_maxproc = 2

# 进程日志记录文件,其中 {install_path} 需要用实际的安装路径代替
master_log = {install_path}/var/log/single_echo.log
# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出
single_use_limit = 250
# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出
single_idle_limit = 180

 

 

      例如当 acl_master 服务器框架程序的安装目录为:/opt/acl,则:

      /opt/acl/libexec: 该目录存储服务器程序(acl_master 程序也存放在该目录下);

      /opt/acl/conf:该目录存放 acl_master 程序配置文件 main.cf;

      /opt/acl/conf/service:该目录存放服务子进程的程序配置文件,该路径由 main.cf 文件指定;

      /opt/acl/var/log:该目录存放日志文件;

      /opt/acl/var/pid:该目录存放进程号文件。

      该程序编译通过后,需要把可执行程序放在 /opt/acl/libexec 目录下,把配置文件放在 /opt/acl/conf/service 目录下。

      在 /opt/acl/sh 下有启动/停止 acl_master 服务进程的控制脚本;运行脚本:./start.sh,然后请用下面方法检查服务是否已经启动:

      ps -ef|grep acl_master # 查看服务器控制进程是否已经启动

      netstat -nap|grep LISTEN|grep 5002 # 查看服务端口号是否已经被监听

      当然,您也可以查看 /opt/acl/var/log/acl_master 日志文件,查看服务进程的启动过程及监听服务是否正常监听。

 

      可以命令行如下测试:telnet 127.0.0.1 5002

       原文地址

       acl_cpp 下载

       acl_cpp 的编译与使用

       更多文章

       个人微博:http://weibo.com/zsxxsz

       QQ 群:242722074

© 著作权归作者所有

郑树新

郑树新

粉丝 104
博文 87
码字总数 161171
作品 2
昌平
程序员
私信 提问
使用 acl 生成向导快速创建服务器程序

在以前有关使用 acl 的技术文章(如:使用 acl::masterthreads 类编写多进程多线程服务器程序 ,用 acl::masteraio 类编写高并发非阻塞服务器程序,使用 acl::master_proc 类编写多进程服务器...

郑树新
2014/09/03
0
0
协作半驻留式服务器程序开发框架 --- 基于 Postfix 服务器框架改造

一、概述  现在大家在和Java, PHP, .net写应用程序时,都会用到一些成熟的服务框架,所以开发效率是比较高的。而在用C/C++写服务器程序时,用的就五花八门了,有些人用ACE, 有些人用ICE(号...

郑树新
2014/08/31
0
2
网络与服务器编程框架库 acl_3.0.14 发布

acl 3.0.14 版本 (项目主页:https://sourceforge.net/projects/acl/) 发布了,acl 是 one Advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/...

郑树新
2013/12/07
2.5K
7
acl 网络通信与服务器框架库示例列表

跨平台网络通信及服务器框架库 --- "acl" 项目里有大量的测试及应用示例,主要有三个示例集合,如下: 1、acl/samples:该目录下的例子主要是基于 libacl 及 libprotocol 两个库的例子 - 1....

郑树新
2014/07/15
0
0
acl_3.4.0 发布,跨平台网络通信与服务器框架

历时一年,acl 跨平台网络通信及服务器框架库发布大版本升级。主要有以下改进: 1、重构网络协程库,支持更多的操作系统平台(Linux/FreeBSD/MacOS/Windows),且支持更多网络事件引擎:epo...

郑树新
2018/05/01
828
8

没有更多内容

加载失败,请刷新页面

加载更多

通过微服务来正确实施SOA

对于组织来说,能够构建、发展和扩展大型应用程序是至关重要的, 但所涉及的挑战使其成为一项艰巨的任务。正因为如此, 微服务凭借能够将单个组件拆分成围绕特定业务功能的独立服务,已成为构建...

Linux就该这么学
15分钟前
2
0
从 Spark 到 Kubernetes — MaxCompute 的云原生开源生态实践之路

2019年5月14日,喜提浙江省科学技术进步一等奖的 MaxCompute 是阿里巴巴自研的 EB 级大数据计算平台。该平台依托阿里云飞天基础架构,是阿里巴巴在10年前做飞天系统的三大件之分布式计算部分...

阿里云官方博客
18分钟前
1
0
使用python来操作redis用法详解

1、redis连接 redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的red...

dragon_tech
18分钟前
2
0
给研发工程师的代码质量利器 | SOFAChannel#5 直播整理

> SOFA:Channel,有趣实用的分布式架构频道。 > > 本文根据 SOFAChannel#5 直播分享整理,主题:给研发工程师的代码质量利器 —— 自动化测试框架 SOFAActs。 > > 回顾视频以及 PPT 查看地址...

SOFAStack
20分钟前
1
0
段错误总结

https://blog.csdn.net/e_road_by_u/article/details/61415732 一、段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问...

悲催的古灵武士
22分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部