Skip to content

Commit e16924c

Browse files
committed
Add my old articles for about Acl development.
1 parent 665b7a7 commit e16924c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+5660
-91
lines changed

about_fiber.md

+313
Large diffs are not rendered by default.

aio.md

+519
Large diffs are not rendered by default.

build_use_fiber.md

+304
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
---
2+
title: 编译使用Acl协程库
3+
date: 2019-03-23 13:08:24
4+
tags: 协程编程
5+
categories: 协程编程
6+
---
7+
8+
## 一、概述
9+
在《使用 acl 协程编写高并发网络服务》和《使用协程方式编写高并发的 WEB 服务》两篇文章中介绍了如何使用 acl 的协程功能编写高并发服务器程序,本文主要介绍如何编译使用 acl 的网络协程库。
10+
11+
## 二、 acl 协程库的依赖关系
12+
目前 acl 协程主要分为 C 库(lib_fiber.a,在 acl/lib_fiber/c 目录下)和 C++库(libfiber_cpp.a,在 acl/lib_fiber/cpp 目录下),其中 lib_fiber_cpp.a 依赖 libfiber.a,具体的依赖关系如下:
13+
![协程库依赖](/img/fiber_depedence.png)
14+
15+
libfiber.a 目前是独立的库,libfiber_cpp.a 依赖 libfiber.a 和 lib_acl_cpp.a,lib_acl_cpp.a 依赖 lib_protocol.a 和 lib_acl.a,lib_protocol.a 依赖 lib_acl.a。
16+
17+
其中,lib_acl.a 为 acl 中的核心基础 C 库,lib_protocol.a 为 acl 中的网络协议(http/icmp/smtp)基础 C 库,lib_acl_cpp 为 C++库,依赖上述两个 C 库;libfiber.a 为独立的网络协程库,仅依赖于系统库,libfiber_cpp.a 为封装了 libfiber.a 的 C++ 库,如果用户所用的 GCC 支持 C++11,则该库还支持更为简洁的创建协程的方式(借助于 C++11中的 lambda 表达式方式)。
18+
19+
## 三、一个简单的例子
20+
下面是一个简单的使用 acl 协程的例子:
21+
22+
```c
23+
#include "lib_acl.h"
24+
#include <stdio.h>
25+
#include <stdlib.h>
26+
#include "fiber/lib_fiber.h"
27+
28+
static int __max_loop = 100;
29+
static int __max_fiber = 10;
30+
static int __stack_size = 64000;
31+
32+
/* 协程处理入口函数 */
33+
static void fiber_main(ACL_FIBER *fiber, void *ctx acl_unused)
34+
{
35+
int i;
36+
37+
/* 两种方式均可以获得当前的协程号 */
38+
assert(acl_fiber_self() == acl_fiber_id(fiber));
39+
40+
for (i = 0; i < __max_loop; i++) {
41+
acl_fiber_yield(); /* 主动让出 CPU 给其它协程 */
42+
printf("fiber-%d\r\n", acl_fiber_self());
43+
}
44+
}
45+
46+
int main(void)
47+
{
48+
int ch, i;
49+
50+
/* 创建协程 */
51+
for (i = 0; i < __max_fiber; i++) {
52+
acl_fiber_create(fiber_main, NULL, __stack_size);
53+
}
54+
55+
printf("---- begin schedule fibers now ----\r\n");
56+
acl_fiber_schedule(); /* 循环调度所有协程,直至所有协程退出 */
57+
printf("---- all fibers exit ----\r\n");
58+
return 0;
59+
}
60+
```
61+
62+
上述例子非常简单,说明了 acl 协程创建、启动和运行过程,如果仅此而已,当然使用协程并没有什么卵用,协程的关键价值在于与网络通信的结合,可以达到高并发、高性能的目的。因此,现实中协程的应用范围主要还是网络服务方面,更为准确的叫法应该是“网络协程”,脱离了“网络”协程基本没啥价值。本文的开头给出了两个链接,指明了网络协程的应用场景及实例。
63+
64+
## 四、编译例子
65+
下面的 Makefile 文件说明了最简单的编译方式:
66+
67+
```
68+
fiber: main.o
69+
gcc -o fiber main.o -L./lib_fiber/lib -L./lib_acl/lib -l_acl -lfiber -lpthread -ldl
70+
main.o: main.c
71+
gcc -c main.c -O3 -DLINUX2 -I./lib_fiber/c/include -I./lib_acl/include
72+
```
73+
该 Makefile 也非常简单,也仅是说明了使用 acl 网络协程库时的编译条件。其中,l_fiber 指定了 acl 的网络协程库,l_acl 指定了 acl 基础库,-lpthread 及 -ldl 指定所依赖的系统库;-DLINUX2 指定 LINUX 平台的编译条件,-I 指定头文件所在位置。
74+
75+
## 五、C++ 示例
76+
上面的例子展示了使用 acl C 协程库的使用方法,同时 acl 也提供了 C++ 类封装,方便 C++ 程序员编写协程应用,下面的例子为使用标准 C++ 编写的协程示例:
77+
78+
```c++
79+
#include <assert.h>
80+
#include <iostream>
81+
#include "acl_cpp/lib_acl.hpp"
82+
#include "fiber/lib_fiber.hpp"
83+
84+
class myfiber : public acl::fiber
85+
{
86+
public:
87+
myfiber(int max_loop) : max_loop_(max_loop) {}
88+
89+
protected:
90+
// @override 实现基类纯虚函数
91+
void run(void)
92+
{
93+
// 两种方式均可以获得当前的协程号
94+
assert(get_id() == acl::fiber::self());
95+
96+
for (int i = 0; i < max_loop_; i++) {
97+
acl::fiber::yield(); // 主动让出 CPU 给其它协程
98+
std::cout << "fiber-" << acl::fiber::self() << std::endl;
99+
}
100+
101+
delete this; // 因为是动态创建的,所以需自动销毁
102+
}
103+
104+
private:
105+
int max_loop_;
106+
107+
~myfiber(void) {}
108+
};
109+
110+
int main(void)
111+
{
112+
int i, max_fiber = 10, max_loop = 10;
113+
114+
for (i = 0; i < max_fiber; i++) {
115+
acl::fiber* fb = new myfiber(max_loop); // 创建协程
116+
fb->start(); // 启动协程
117+
}
118+
119+
std::cout << "---- begin schedule fibers now ----" << std::endl;
120+
acl::fiber::schedule(); // 循环调度所有协程,直至所有协程退出
121+
std::cout << "---- all fibers exit ----" << std::endl;
122+
123+
return 0;
124+
}
125+
```
126+
127+
该例子也非常简单,实现了与上面 C 示例相同的功能,只是采用 C++ 而已。用户首先需要定义自己的类,其继承于 acl::fiber 协程类,然后实现协程类中的纯虚方法:run(),当调用协程的启动方法 start() 时,acl::fiber 基类会自动回调纯虚方法 run()。
128+
129+
该 C++ 示例的 Makefile 与 C 的有所不同,内容如下:
130+
131+
```
132+
fiber: main.o
133+
g++ -o fiber main.o -L./lib_fiber/lib -lfiber_cpp \
134+
-L./lib_acl_cpp/lib -l_acl_cpp \
135+
-L./lib_acl/lib -l_acl -lfiber \
136+
-lpthread -ldl
137+
main.o: main.cpp
138+
g++ -O3 -Wall -c main.cpp -DLINUX2 -I./lib_fiber/cpp/include \
139+
-I./lib_acl_cpp/include
140+
```
141+
142+
## 六、C++11 示例
143+
acl 的协程库同时提供了支持 C++11 方式的调用方法,使创建协程更加方便,代码如下:
144+
145+
```c++
146+
#include <iostream>
147+
#include "acl_cpp/lib_acl.hpp"
148+
#include "fiber/lib_fiber.hpp"
149+
150+
static void fiber_main(int max_loop)
151+
{
152+
for (int i = 0; i < max_loop; i++) {
153+
acl::fiber::yield(); // 主动让出 CPU 给其它协程
154+
std::cout << "fiber-" << acl::fiber::self() << std::endl;
155+
}
156+
}
157+
158+
int main(void)
159+
{
160+
int i, max_fiber = 10, max_loop = 10;
161+
162+
for (i = 0; i < max_fiber; i++) {
163+
go[=] { // 采用 c++11 的 lambad 表达式方式创建协程
164+
fiber_main(max_loop); // 进入协程处理函数
165+
};
166+
}
167+
168+
std::cout << "---- begin schedule fibers now ----" << std::endl;
169+
// 循环调度所有协程,直至所有协程退出
170+
acl::fiber::schedule();
171+
std::cout << "---- all fibers exit ----" << std::endl;
172+
173+
return 0;
174+
}
175+
```
176+
177+
使用 C++11 方式创建协程是不是感觉更加简洁?
178+
179+
同样下面给出 makefile 内容:
180+
181+
```
182+
fiber: main.o
183+
g++ -o fiber main.o -L../../../lib -lfiber_cpp \
184+
-L../../../../lib_acl_cpp/lib -l_acl_cpp \
185+
-L../../../../lib_acl/lib -l_acl -lfiber \
186+
-lpthread -ldl
187+
main.o: main.cpp
188+
g++ -std=c++11 -O3 -Wall -c main.cpp -DLINUX2 -I.. -I../../../cpp/include \
189+
-I../../../../lib_acl_cpp/include
190+
```
191+
192+
## 七、基于协程的网络服务
193+
前面提到了“如果协程不与网络应用结合,则不会发挥其价值“,因此,下面就给出一个具体的基于协程的网络服务器程序:
194+
195+
```c++
196+
#include <iostream>
197+
#include "acl_cpp/lib_acl.hpp"
198+
#include "fiber/lib_fiber.hpp"
199+
200+
class fiber_client : public acl::fiber
201+
{
202+
public:
203+
fiber_client(acl::socket_stream* conn) : conn_(conn) {}
204+
205+
protected:
206+
// @override 实现基类纯虚函数
207+
void run(void)
208+
{
209+
std::cout << "fiber-" << acl::fiber::self()
210+
<< ": fd=" << conn_->sock_handle()
211+
<< ", addr=" << conn_->get_peer() << std::endl;
212+
echo();
213+
delete this; // 因为是动态创建的,所以需自动销毁
214+
}
215+
216+
private:
217+
acl::socket_stream* conn_;
218+
219+
~fiber_client(void)
220+
{
221+
delete conn_;
222+
}
223+
224+
void echo(void)
225+
{
226+
char buf[8192];
227+
228+
// 从客户端读取数据并回显
229+
while (!conn_->eof()) {
230+
int ret = conn_->read(buf, sizeof(buf), false);
231+
if (ret == -1) {
232+
std::cout << "read " << acl::last_serror() << std::endl;
233+
break;
234+
}
235+
if (conn_->write(buf, ret) == -1) {
236+
std::cout << "write " << acl::last_serror() << std::endl;
237+
break;
238+
}
239+
}
240+
}
241+
};
242+
243+
class fiber_server : public acl::fiber
244+
{
245+
public:
246+
fiber_server(const char* addr) : addr_(addr) {}
247+
248+
protected:
249+
// @override
250+
void run(void)
251+
{
252+
// 监听服务地址
253+
acl::server_socket ss;
254+
if (ss.open(addr_) == false) {
255+
std::cout << "listen " << addr_.c_str() << " error" << std::endl;
256+
delete this;
257+
return;
258+
}
259+
260+
std::cout << "listen " << addr_.c_str() << " ok" << std::endl;
261+
262+
while (true) {
263+
// 等待接收客户端连接
264+
acl::socket_stream* conn = ss.accept();
265+
if (conn == NULL) {
266+
std::cout << "accept error" << std::endl;
267+
break;
268+
}
269+
270+
// 创建客户端处理协程
271+
acl::fiber* fb = new fiber_client(conn);
272+
fb->start();
273+
}
274+
275+
delete this;
276+
}
277+
278+
private:
279+
acl::string addr_;
280+
281+
~fiber_server(void) {}
282+
};
283+
284+
int main(void)
285+
{
286+
const char* addr = "127.0.0.1:8089";
287+
288+
acl::fiber* fb = new fiber_server(addr); // 创建监听服务协程
289+
fb->start(); // 启动监听协程
290+
291+
// 循环调度所有协程,直至所有协程退出
292+
acl::fiber::schedule();
293+
294+
return 0;
295+
}
296+
```
297+
298+
麻雀虽小,五脏俱全,该示例简明扼要地说明了如何使用 acl 的网络协程库编写支持高并发的网络服务应用。
299+
300+
## 八、参考
301+
在 acl/lib_fiber/samples/ 目录下,还有大量的使用 acl 协程的例子,包括:定时器、简单聊天服务、mysql 访问协程化、redis 访问协程化、域名解析协程化等。
302+
303+
github:https://github.com/acl-dev/acl
304+
gitee: http://git.oschina.net/acl-dev/acl

configure.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
title: 配置文件的读取
3+
date: 2009-11-03 12:43
4+
categories: 配置文件
5+
---
6+
7+
配置文件的读取是程序中必要部分,虽然不算复杂,但如果每次都写配置文件的分析提取代码也是件烦人的事。现在流行的配置文件格式有:ini,xml ,简单name-value对等格式,ACL库中实现了最简单的 name-value对格式的配置文件,该文件格式有点类似于 xinetd.conf 的格式,文件格式如下:
8+
9+
10+
test.cf:
11+
12+
```
13+
service myapp {
14+
15+
my_addr = 127.0.0.1
16+
17+
my_port = 80
18+
19+
my_list = www.test1.com, www.test2.com, www.test3.com, \
20+
21+
www.test4.com, www.test5.com, www.test6.com
22+
23+
...
24+
25+
}
26+
```
27+
28+
29+
其中的 "\" 是连接符,可以把折行的数据连接起来。
30+
31+
下面的例子读取该配置文件并进行解析:
32+
33+
```c
34+
static int var_cfg_my_port;
35+
36+
static ACL_CFG_INT_TABLE __conf_int_tab[] = {
37+
/* 配置项名称, 配置项缺省值, 存储配置项值的地址, 保留字, 保留字 */
38+
{ "my_port", 8080, &var_cfg_my_port, 0, 0 },
39+
{ 0, 0 , 0, 0, 0 }
40+
};
41+
42+
static char *var_cfg_my_addr;
43+
static char *var_cfg_my_list;
44+
45+
static ACL_CFG_STR_TABLE __conf_str_tab[] = {
46+
/* 配置项名称, 配置项缺省值, 存储配置项值的地址 */
47+
{ "my_addr", "192.168.0.1", &var_cfg_my_addr },
48+
{ "my_list", "www.test.com", &var_cfg_my_list },
49+
{ 0, 0, 0 }
50+
};
51+
52+
static int var_cfg_my_check;
53+
54+
static ACL_CFG_BOOL_TABLE __conf_bool_tab[] = {
55+
/* 配置项名称, 配置项缺省值, 存储配置项值的地址 */
56+
{ "my_check", 0, &var_cfg_my_check },
57+
{ 0, 0, 0 }
58+
};
59+
60+
void test(void)
61+
{
62+
ACL_XINETD_CFG_PARSER *cfg; // 配置解析对象
63+
64+
cfg = acl_xinetd_cfg_load("test.cf"); // 读取并解析配置文件
65+
acl_xinetd_params_int_table(cfg, __conf_int_tab); // 读取所有 int 类型的配置项
66+
acl_xinetd_params_str_table(cfg, __conf_str_tab); // 读取所有字符串类型的配置项
67+
acl_xinetd_params_bool_table(cfg, __conf_bool_tab); // 读取所有 bool 型的配置项
68+
69+
acl_xinetd_cfg_free(cfg); // 释放内存
70+
}
71+
```
72+
通过调用 acl_xinetd_params_xxx_table() 函数,直接将配置项的值赋给变量,这样省去了很多麻烦。

0 commit comments

Comments
 (0)