### C++ Example: Simple Thread Creation and Management with ACL Source: https://acl-dev.cn/2019/04/07/fiber This C++ example demonstrates how to create and manage simple threads using the ACL library. It involves defining a thread class, starting multiple threads, and waiting for them to complete. Dependencies include the acl_cpp/lib_acl.hpp header. ```C++ #include class mythread : public acl::thread { public: mythread(void) {} ~mythread(void) {} private: // 实现基类中纯虚方法,当线程启动时该方法将被回调 // @override void* run(void) { for (int i = 0; i < 10; i++) { printf("thread-%lu: running ...\r\n", acl::thread::self()); } return NULL; } }; int main(void) { std::vector threads; for (int i = 0; i < 10; i++) { acl::thread* thr = new mythread; threads.push_back(thr); thr->start(); // 启动线程 } for (std::vector::iterator it = threads.begin(); it != threads.end(); ++it) { (*it)->wait(); // 等待线程退出 delete *it; } return 0; } ``` -------------------------------- ### Compile and Install ACL Library on Linux/Unix using Make Source: https://acl-dev.cn/2019/04/07/fiber Compiles the ACL library and installs it to system directories using the make utility. The compiled libraries (libacl_all.a, libfiber_cpp.a, libfiber.a) are placed in /usr/lib/, and header files in /usr/include/acl-lib/. ```bash make && make packinstall ``` -------------------------------- ### Create and Start Redis Pipeline Connection in C++ Source: https://acl-dev.cn/2015/02/10/redis_client This snippet demonstrates how to initialize and start a Redis pipeline connection using the acl::redis_client_pipeline class. It requires specifying the Redis server address and then calling the start() method to initiate the pipeline in a separate thread. This sets up the client for pipelined Redis command execution. ```cpp const char* redis_addr = "127.0.0.1:6379"; acl::redis_client_pipeline pipeline(redis_addr); pipeline.start(); // 创建独立线程并启动 pipeline 模式 ``` -------------------------------- ### C Coroutine Example Source: https://acl-dev.cn/2019/03/23/build_use_fiber Demonstrates the creation, starting, and running of coroutines using the ACL C library. It includes functions for yielding control and printing coroutine IDs. This example is foundational for understanding coroutine behavior. ```c #include "lib_acl.h" #include #include #include "fiber/lib_fiber.h" static int __max_loop = 100; static int __max_fiber = 10; static int __stack_size = 64000; /* 协程处理入口函数 */ static void fiber_main(ACL_FIBER *fiber, void *ctx acl_unused) { int i; /* 两种方式均可以获得当前的协程号 */ assert(acl_fiber_self() == acl_fiber_id(fiber)); for (i = 0; i < __max_loop; i++) { acl_fiber_yield(); /* 主动让出 CPU 给其它协程 */ printf("fiber-%d\r\n", acl_fiber_self()); } } int main(void) { int ch, i; /* 创建协程 */ for (i = 0; i < __max_fiber; i++) { acl_fiber_create(fiber_main, NULL, __stack_size); } printf("---- begin schedule fibers now ----\r\n"); acl_fiber_schedule(); /* 循环调度所有协程,直至所有协程退出 */ printf("---- all fibers exit ----\r\n"); return 0; } ``` -------------------------------- ### Coroutine Redis Client Example (Multi-Threaded) Source: https://acl-dev.cn/2019/04/07/fiber This C++ code demonstrates making the Acl Redis client library coroutine-friendly in a multi-threaded environment. It features a `fiber_redis` class for Redis operations and a `mythread` class that manages a separate coroutine scheduler per thread. The `main` function initializes a shared Redis cluster, binds it to threads using `bind_thread(true)`, and starts multiple threads, each running its own set of coroutines. ```cpp #include #include // 每个协程共享相同的 cluster 对象,向 redis-server 中添加数据 class fiber_redis : public acl::fiber { public: fiber_redis(acl::redis_client_cluster& cluster) : cluster_(cluster) {} private: ~fiber_redis(void) {} private: acl::redis_client_cluster& cluster_; // @override void run(void) { const char* key = "hash-key"; for (int i = 0; i < 100; i++) { acl::redis cmd(&cluster_); acl::string name, val; name.format("hash-name-%d", i); val.format("hash-val-%d", i); if (cmd.hset(key, name, val) == -1) { printf("hset error: %s, key=%s, name=%s\r\n", cmd.result_error(), key, name.c_str()); break; } } delete this; } }; // 每个线程运行一个独立的协程调度器 class mythread : public acl::thread { public: mythread(acl::redis_client_cluster& cluster) : cluster_(cluster) {} ~mythread(void) {} private: acl::redis_client_cluster& cluster_; // @override void* run(void) { for (int i = 0; i < 100; i++) { acl::fiber* fb = new fiber_redis(cluster_ ); fb->start(); } acl::fiber::schedule(); return NULL; } }; int main(void) { const char* redis_addr = "127.0.0.1:6379"; acl::redis_client_cluster cluster; cluster.set(redis_addr, 0); cluster.bind_thread(true); // 创建多个线程,共享 redis 集群连接池管理对象:cluster,即所有线程中的 // 所有协程共享同一个 cluster 集群管理对象 std::vector threads; for (int i = 0; i < 4; i++) { acl::thread* thr = new mythread(cluster); threads.push_back(thr); thr->start(); } for (std::vector::iterator it = threads.begin(); it != threads.end(); ++it) { (*it)->wait(); delete *it; } return 0; } ``` -------------------------------- ### ACL HTTP Client Example Implementation Source: https://acl-dev.cn/2010/01/11/http_dowload This C code provides a complete example of an HTTP client using the ACL library. It demonstrates how to parse command-line arguments for URL, method, proxy, and dump file, initialize the ACL library, create and configure an HTTP request, send the request, receive and process the response headers and body, and finally free the HTTP utility object. Error handling and usage instructions are included. ```c #include "lib_acl.h" #include "lib_protocol.h" static void get_url(const char *method, const char *url, const char *proxy, const char *dump, int out) { /* 创建 HTTP_UTIL 请求对象 */ HTTP_UTIL *http = http_util_req_new(url, method); int ret; /* 如果设定代理服务器,则连接代理服务器地址, * 否则使用 HTTP 请求头里指定的地址 */ if (proxy && *proxy) http_util_set_req_proxy(http, proxy); /* 设置转储文件 */ if (dump && *dump) http_util_set_dump_file(http, dump); /* 输出 HTTP 请求头内容 */ http_hdr_print(&http->hdr_req->hdr, "---request hdr---"); /* 连接远程 http 服务器 */ if (http_util_req_open(http) < 0) { printf("open connection(%s) error\n", http->server_addr); http_util_free(http); return; } /* 读取 HTTP 服务器响应头*/ ret = http_util_get_res_hdr(http); if (ret < 0) { printf("get reply http header error\n"); http_util_free(http); return; } /* 输出 HTTP 响应头 */ http_hdr_print(&http->hdr_res->hdr, "--- reply http header ---"); /* 如果有数据体则开始读取 HTTP 响应数据体部分 */ while (1) { char buf[4096]; ret = http_util_get_res_body(http, buf, sizeof(buf) - 1); if (ret <= 0) break; buf[ret] = 0; if (out) printf("%s", buf); } http_util_free(http); } static void usage(const char *procname) { printf("usage: %s -h[help] -t method -r url -f dump_file -o[output] -X proxy_addr\n" "example: %s -t GET -r http://www.sina.com.cn/ -f url_dump.txt\n", procname, procname); } int main(int argc, char *argv[]) { int ch, out = 0; char url[256], dump[256], proxy[256], method[32]; acl_init(); /* 初始化 acl 库 */ ACL_SAFE_STRNCPY(method, "GET", sizeof(method)); url[0] = 0; dump[0] = 0; proxy[0] = 0; while ((ch = getopt(argc, argv, "hor:t:f:X:")) > 0) { switch (ch) { case 'h': usage(argv[0]); return (0); case 'o': out = 1; break; case 'r': ACL_SAFE_STRNCPY(url, optarg, sizeof(url)); break; case 't': ACL_SAFE_STRNCPY(method, optarg, sizeof(method)); break; case 'f': ACL_SAFE_STRNCPY(dump, optarg, sizeof(dump)); break; case 'X': ACL_SAFE_STRNCPY(proxy, optarg, sizeof(proxy)); break; default: break; } } if (url[0] == 0) { usage(argv[0]); return (0); } ``` -------------------------------- ### Compiling and Installing acl_master and master_ctl Source: https://acl-dev.cn/2023/06/10/using_master These commands outline the process for compiling the Acl base library, the acl_master daemon, and the master_ctl command-line tool. It also covers the installation steps to deploy these components to their respective directories. ```shell cd acl make cd app/master/daemon make make install cd ../tools/master_ctl make make install cd ../../dist/master ./setup.sh /opt/soft/acl-master ``` -------------------------------- ### C++ Example: Simple Coroutine Implementation with ACL Source: https://acl-dev.cn/2019/04/07/fiber This C++ example shows how to implement and run simple coroutines using the ACL library. It defines a coroutine class, starts multiple coroutines, and then schedules them for execution. The key function is `acl::fiber::yield()` for yielding control. ```C++ #include class myfiber : public acl::fiber { public: myfiber(void) {} ~myfiber(void) {} private: // 实现基类纯虚方法,当调用 fiber::start() 时,该方法将被调用 // @override void run(void) { for (int i = 0; i < 10; i++) { printf("hello world! the fiber is %d\r\n", acl::fiber::self()); acl::fiber::yield(); // 让出CPU运行权给其它协程 } } }; int main(void) { std::vector fibers; for (int i = 0; i < 10; i++) { acl::fiber* fb = new myfiber; fibers.push_back(fb); fb->start(); // 启动一个协程 } acl::fiber::schedule(); // 启用协程调度器 for (std::vector::iterator it = fibers.begin(); it != fibers.end(); ++it) { delete *it; } } ``` -------------------------------- ### Multi-threaded Coroutine Server Example in C++ Source: https://acl-dev.cn/2019/04/07/fiber A C++ example demonstrating how to build a multi-threaded server using ACL coroutines. Each thread runs an independent coroutine scheduler, allowing for efficient utilization of multi-core processors. The code includes classes for handling client connections (fiber_echo), listening for connections (fiber_listen), and managing threads (thread_server). ```cpp #include #include // 客户端协程处理类,用来回显客户发送的内容,每一个客户端连接绑定一个独立的协程 class fiber_echo : public acl::fiber { public: fiber_echo(acl::socket_stream* conn) : conn_(conn) {} private: acl::socket_stream* conn_; ~fiber_echo(void) { delete conn_; } private: // @override void run(void) { char buf[8192]; while (true) { int ret = conn_->read(buf, sizeof(buf), false); if (ret == -1) { break; } if (conn_->write(buf, ret) != ret) { break; } } delete this; // 自销毁动态创建的协程对象 } }; // 独立的协程过程,接收客户端连接,并将接收的连接与新创建的协程进行绑定 class fiber_listen : public acl::fiber { public: fiber_listen(acl::server_socket& listener) : listener_(listener) {} private: acl::server_socket& listener_; ~fiber_listen(void) {} private: // @override void run(void) { while (true) { acl::socket_stream* conn = listener_.accept(); // 等待客户端连接 if (conn == NULL) { printf("accept failed: %s\r\n", acl::last_serror()); break; } // 创建并启动单独的协程处理客户端连接 acl::fiber* fb = new fiber_echo(conn); fb->start(); } delete this; } }; // 独立的线程调度类 class thread_server : public acl::thread { public: thread_server(acl::server_socket& listener) : listener_(listener) {} ~thread_server(void) {} private: acl::server_socket& listener_; // @override void* run(void) { // 创建并启动独立的监听协程,接受客户端连接 acl::fiber* fb = new fiber_listen(listener_); fb->start(); // 启动协程调度器 ac l::fiber::schedule(); // 内部处于死循环过程 return NULL; } }; int main(void) { const char* addr = "127.0.0.1:8800"; ac l::server_socket listener; // 监听本地地址 if (listener.open(addr) == false) { printf("listen %s error %s\n", addr, acl::last_serror()); return 1; } std::vector threads; // 创建多个独立的线程对象,每个线程启用独立的协程调度过程 for (int i = 0; i < 4; i++) { ac l::thread* thr = new thread_server(listener); threads.push_back(thr); thr->start(); } for (std::vector::iterator it = threads.begin(); it != threads.end(); ++it) { (*it)->wait(); delete *it; } return 0; } ``` -------------------------------- ### Makefile for C++11 Coroutine Example Source: https://acl-dev.cn/2019/03/23/build_use_fiber Makefile 用于编译 C++11 协程示例。它定义了如何链接 acl 协程库和其他必要的库,以及如何编译 C++ 源文件,指定了 C++11 标准和优化选项。 ```makefile fiber: main.o g++ -o fiber main.o -L../../../lib -lfiber_cpp \ -L../../../../lib_acl_cpp/lib -l_acl_cpp \ -L../../../../lib_acl/lib -l_acl -lfiber \ -lpthread -ldl main.o: main.cpp g++ -std=c++11 -O3 -Wall -c main.cpp -DLINUX2 -I.. -I../../../cpp/include \ -I../../../../lib_acl_cpp/include ``` -------------------------------- ### Executing url_get to Standard Output (C++) Source: https://acl-dev.cn/2010/01/11/http_dowload This example demonstrates executing the 'url_get' client to fetch a web page from 'http://www.sina.com' and display the output directly to the standard output. It shows the command-line invocation and a representation of the expected HTTP response. ```text 输入: ./url_get -t GET -r http://www.sina.com -o, 该命令是获取 www.sina.com 页面并输出至标准输出,得到的结果为: HTTP/1.0 301 Moved Permanently Date: Tue, 12 Jan 2010 01:54:39 GMT Server: Apache Location: http://www.sina.com.cn/ Cache-Control: max-age=3600 Expires: Tue, 12 Jan 2010 02:54:39 GMT Vary: Accept-Encoding Content-Length: 231 Content-Type: text/html; charset=iso-8859-1 Age: 265 X-Cache: HIT from tj175-135.sina.com.cn Connection: close --------------- end ----------------- 301 Moved Permanently

Moved Permanently

The document has moved here.

``` -------------------------------- ### Starting and Stopping acl_master Service Source: https://acl-dev.cn/2023/06/10/using_master These scripts and commands are used to manage the acl_master service. 'start.sh' and 'stop.sh' are general scripts, while 'master.sh' offers start, stop, and reload functionality on Linux. On CentOS with RPM installation, 'service' commands can be used. ```shell # Using scripts in installation directory /opt/soft/acl-master/sh/start.sh /opt/soft/acl-master/sh/stop.sh /opt/soft/acl-master/sh/master.sh start # Using service command on CentOS service acl-master start service acl-master stop ``` -------------------------------- ### High-Concurrency WEB Service with Coroutines Source: https://acl-dev.cn/page/2 Presents a more complex and practical example of a coroutine-based WEB server program using the ACL coroutine library. This showcases building high-concurrency network services by effectively managing requests through coroutines. ```c++ #include #include #include #include // Example of a coroutine handler for a WEB request (inferred) void handle_web_request(acl::fiber* self) { acl::tcp_socket sock; // Assume sock is connected and data is received std::string request_data; sock.read(request_data.data(), request_data.size()); std::cout << "Received request: " << request_data << std::endl; std::string response = "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello, World!"; sock.write(response.c_str(), response.length()); sock.close(); self->yield(ACL_YIELD_TYPE_FINISH); } // Example of setting up the server (inferred) int main() { // Initialize ACL fiber system acl_fiber_context_init(); // Create a listening socket acl::tcp_server server; if (!server.listen(8080)) { std::cerr << "Failed to listen on port 8080" << std::endl; return 1; } while (true) { acl::tcp_socket* client_sock = server.accept(); if (client_sock == nullptr) { continue; } // Create a new fiber for each client connection acl::fiber* fiber = new acl::fiber(handle_web_request); // Pass the client socket to the fiber (implementation detail) fiber->set_private_data(client_sock); fiber->resume(); } return 0; } ``` -------------------------------- ### Executing url_get to Dump File (C++) Source: https://acl-dev.cn/2010/01/11/http_dowload This example shows how to use the 'url_get' client to download a web page from 'http://www.sina.com' and save its content to a file named 'dump.txt'. It illustrates the command-line usage for this operation. ```text 如果想把页面转存至文件中,可以输入:./url_get -t GET -r http://www.sina.com -f dump.txt, 这样就会把新浪的首页下载并存储于 dump.txt 文件中。 ``` -------------------------------- ### C++ Object Serialization with ACL Source: https://acl-dev.cn/page/2 Demonstrates advanced examples of using the ACL library for C++ object serialization and deserialization. This is useful for data exchange between modules in network applications, handling complex scenarios like multiple inheritance. ```c++ #pragma once #include // Example struct definition (based on description) struct MyStruct { int id; std::string name; }; // Example serialization function (inferred) void serialize_my_struct(acl::basic_stream& stream, const MyStruct& data) { stream << data.id << data.name; } // Example deserialization function (inferred) void deserialize_my_struct(acl::basic_stream& stream, MyStruct& data) { stream >> data.id >> data.name; } ``` -------------------------------- ### Coroutine Redis Client Example (Single-Threaded) Source: https://acl-dev.cn/2019/04/07/fiber This C++ code demonstrates how to make the Acl Redis client library coroutine-friendly in a single-threaded environment. It defines a `fiber_redis` class that inherits from `acl::fiber` to perform HSET operations on a Redis cluster. The `run` method iterates and sends HSET commands, and the `main` function initializes the Redis cluster and starts multiple `fiber_redis` instances. ```cpp #include #include class fiber_redis : public acl::fiber { public: fiber_redis(acl::redis_client_cluster& cluster) : cluster_(cluster) {} private: ~fiber_redis(void) {} private: acl::redis_client_cluster& cluster_; // @override void run(void) { const char* key = "hash-key"; for (int i = 0; i < 100; i++) { acl::redis cmd(&cluster_); acl::string name, val; name.format("hash-name-%d", i); val.format("hash-val-%d", i); if (cmd.hset(key, name, val) == -1) { printf("hset error: %s, key=%s, name=%s\r\n", cmd.result_error(), key, name.c_str()); break; } } delete this; } }; int main(void) { const char* redis_addr = "127.0.0.1:6379"; acl::redis_client_cluster cluster; cluster.set(redis_addr, 0); for (int i = 0; i < 100; i++) { acl::fiber* fb = new fiber_redis(cluster); fb->start(); } acl::fiber::schedule(); return 0; } ``` -------------------------------- ### Build and Usage of url_get HTTP Client (C++) Source: https://acl-dev.cn/2010/01/11/http_dowload This snippet shows the C++ code for compiling and running a command-line HTTP client named 'url_get'. It includes instructions on how to build the client and provides a help message detailing its usage, including options for specifying the HTTP method, URL, dump file, output, and proxy address. ```text get_url(method, url, proxy, dump, out); return (0); } 编译成功后,运行 ./url_get -h 会给出如下提示: usage: ./url_get -h[help] -t method -r url -f dump_file -o[output] -X proxy_addr example: ./url_get -t GET -r http://www.sina.com.cn/ -f url_dump.txt ``` -------------------------------- ### C++ CGI HttpServlet Example Source: https://acl-dev.cn/2012/05/20/http_servlet This C++ code implements a CGI program using the acl::HttpServlet class. It handles HTTP GET and POST requests, demonstrating session attribute management, cookie manipulation (setting and retrieving), parameter retrieval, and building an XML response body. It requires the acl library and can be compiled and run as a CGI executable. ```cpp #include "lib_acl.hpp" using namespace acl; ////////////////////////////////////////////////////////////////////////// class http_servlet : public HttpServlet { public: htp_servlet(void) { } ~http_servlet(void) { } // 实现处理 HTTP GET 请求的功能函数 bool doGet(HttpServletRequest& req, HttpServletResponse& res) { return doPost(req, res); } // 实现处理 HTTP POST 请求的功能函数 bool doPost(HttpServletRequest& req, HttpServletResponse& res) { // 获得某浏览器用户的 session 的某个变量值,如果不存在则设置一个 const char* sid = req.getSession().getAttribute("sid"); if (sid == NULL || *sid == 0) req.getSession().setAttribute("sid", "xxxxxx"); // 再取一次该浏览器用户的 session 的某个属性值 sid = req.getSession().getAttribute("sid"); // 取得浏览器发来的两个 cookie 值 const char* cookie1 = req.getCookieValue("name1"); const char* cookie2 = req.getCookieValue("name2"); // 开始创建 HTTP 响应头 // 设置 cookie res.addCookie("name1", "value1"); // 设置具有作用域和过期时间的 cookie res.addCookie("name2", "value2", ".test.com", "/", 3600 * 24); // res.setStatus(200); // 可以设置返回的状态码 // 两种方式都可以设置字符集 if (0) res.setContentType("text/xml; charset=gb2312"); else { // 先设置数据类型 res.setContentType("text/xml"); // 再设置数据字符集 res.setCharacterEncoding("gb2312"); } // 获得浏览器请求的两个参数值 const char* param1 = req.getParameter("name1"); const char* param2 = req.getParameter("name2"); // 创建 xml 格式的数据体 xml body; body.get_root().add_child("root", true) .add_child("sessions", true) .add_child("session", true) .add_attr("sid", sid ? sid : "null") .get_parent() .get_parent() .add_child("cookies", true) .add_child("cookie", true) .add_attr("name1", cookie1 ? cookie1 : "null") .get_parent() .add_child("cookie", true) .add_attr("name2", cookie2 ? cookie2 : "null") .get_parent() .get_parent() .add_child("params", true) .add_child("param", true) .add_attr("name1", param1 ? param1 : "null") .get_parent() .add_child("param", true) .add_attr("name2", param2 ? param2 : "null"); string buf; body.build_xml(buf); // 在http 响应头中设置数据体长度 res.setContentLength(buf.length()); // 发送 http 响应头 if (res.sendHeader() == false) return false; // 发送 http 响应体 if (res.write(buf) == false) return false; return true; } }; ////////////////////////////////////////////////////////////////////////// int main(void) { #ifdef WIN32 acl::acl_cpp_init(); // win32 环境下需要初始化库 #endif http_servlet servle; // cgi 开始运行 servlet.doRun("127.0.0.1:11211"); // 开始运行,并设定 memcached 的服务地址为:127.0.0.1:11211 // 运行完毕,程序退出 return 0; } ``` -------------------------------- ### redis_builder Command-Line Interface Source: https://acl-dev.cn/2015/04/20/redis_builder Demonstrates the command-line arguments and usage for the redis_builder tool. It includes options for specifying Redis addresses, commands, passwords, new nodes, and configuration files. The examples show how to create, manage, and inspect Redis clusters. ```bash ./redis_build -h usage: redis_builder.exe -h[help] -s redis_addr[ip:port] -a cmd[nodes|slots|create|add_node|del_node|node_id|reshard] -p passwd -N new_node[ip:port] -S [add node as slave] -f configure_file for samples: ./redis_builder -s 127.0.0.1:6379 -a create -f cluster.xml ./redis_builder -s 127.0.0.1:6379 -a nodes ./redis_builder -s 127.0.0.1:6379 -a slots ./redis_builder -s 127.0.0.1:6379 -a del_node -I node_id ./redis_builder -s 127.0.0.1:6379 -a node_id ./redis_builder -s 127.0.0.1:6379 -a reshard ./redis_builder -s 127.0.0.1:6379 -a add_node -N 127.0.0.1:6380 -S ``` -------------------------------- ### ACL Library Compilation with Static SSL Linking (OpenSSL Example) Source: https://acl-dev.cn/2020/01/15/ssl Instructions on how to compile the ACL library with static linking for SSL libraries, using OpenSSL as an example. ```APIDOC ## Building ACL Library with Static SSL ### Description This section details how to compile the ACL library to statically link against SSL libraries, using OpenSSL as an example. This is an alternative to the default dynamic loading. ### Method Shell Command ### Endpoint N/A ### Parameters #### Command Line Arguments - **OPENSSL_STATIC=yes** - Compile option to enable static linking for OpenSSL. ### Request Example ```bash cd acl; make OPENSSL_STATIC=yes ``` ### Response #### Success Response Compilation of the ACL library with static SSL linking is successful. #### Response Example N/A ``` -------------------------------- ### C++ Asynchronous Server Implementation with ACL Source: https://acl-dev.cn/2012/04/04/aio This C++ code demonstrates the core logic of an asynchronous server using the ACL library. It sets up an asynchronous event loop, listens for incoming connections, and defines callback handlers for accepting new clients and managing their read/write operations. The server echoes received data back to the client and handles 'quit' and 'stop' commands. Dependencies include ACL library headers like 'aio_handle.hpp', 'aio_istream.hpp', etc. It takes no explicit input arguments but listens on '127.0.0.1:9001'. ```cpp #include #include #include "aio_handle.hpp" #include "aio_istream.hpp" #include "aio_listen_stream.hpp" #include "aio_socket_stream.hpp" using namespace acl; /** * 异步客户端流的回调类的子类 */ class io_callback : public aio_callback { public: io_callback(aio_socket_stream* client) : client_(client) , i_(0) { } ~io_callback() { std::cout << "delete io_callback now ..." << std::endl; } /** * 实现父类中的虚函数,客户端流的读成功回调过程 * @param data {char*} 读到的数据地址 * @param len {int} 读到的数据长度 * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 */ bool read_callback(char* data, int len) { i_++; if (i_ < 10) std::cout << ">>gets(i:" << i_ << "): " << data; // 如果远程客户端希望退出,则关闭之 if (strncasecmp(data, "quit", 4) == 0) { client_->format("Bye!\r\n"); client_->close(); } // 如果远程客户端希望服务端也关闭,则中止异步事件过程 else if (strncasecmp(data, "stop", 4) == 0) { client_->format("Stop now!\r\n"); client_->close(); // 关闭远程异步流 // 通知异步引擎关闭循环过程 client_->get_handle().stop(); } // 向远程客户端回写收到的数据 client_->write(data, len); return (true); } /** * 实现父类中的虚函数,客户端流的写成功回调过程 * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 */ bool write_callback() { return (true); } /** * 实现父类中的虚函数,客户端流的关闭回调过程 */ void close_callback() { // 必须在此处删除该动态分配的回调类对象以防止内存泄露 delete this; } /** * 实现父类中的虚函数,客户端流的超时回调过程 * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 */ bool timeout_callback() { std::cout << "Timeout ..." << std::endl; return (true); } private: aio_socket_stream* client_; int i_; }; /** * 异步监听流的回调类的子类 */ class io_accept_callback : public aio_accept_callback { public: io_accept_callback() {} ~io_accept_callback() { printf(">>io_accept_callback over!\n"); } /** * 基类虚函数,当有新连接到达后调用此回调过程 * @param client {aio_socket_stream*} 异步客户端流 * @return {bool} 返回 true 以通知监听流继续监听 */ bool accept_callback(aio_socket_stream* client) { // 创建异步客户端流的回调对象并与该异步流进行绑定 io_callback* callback = new io_callback(client); // 注册异步流的读回调过程 client->add_read_callback(callback); // 注册异步流的写回调过程 client->add_write_callback(callback); // 注册异步流的关闭回调过程 client->add_close_callback(callback); // 注册异步流的超时回调过程 client->add_timeout_callback(callback); // 从异步流读一行数据 client->gets(10, false); return (true); } }; int main(int argc, char* argv[]) { // 初始化ACL库(尤其是在WIN32下一定要调用此函数,在UNIX平台下可不调用) acl_cpp_init(); // 构建异步引擎类对象 aio_handle handle(ENGINE_KERNEL); // 创建监听异步流 aio_listen_stream* sstream = new aio_listen_stream(&handle); const char* addr = "127.0.0.1:9001"; // 监听指定的地址 if (sstream->open(addr) == false) { std::cout << "open " << addr << " error!" << std::endl; sstream->close(); // XXX: 为了保证能关闭监听流,应在此处再 check 一下 handle.check(); getchar(); return (1); } // 创建回调类对象,当有新连接到达时自动调用此类对象的回调过程 io_accept_callback callback; sstream->add_accept_callback(&callback); std::cout << "Listen: " << addr << " ok!" << std::endl; while (true) { // 如果返回 false 则表示不再继续,需要退出 if (handle.check() == false) { std::cout << "aio_server stop now ..." << std::endl; break; } } // 关闭监听流并释放流对象 sstream->close(); // XXX: 为了保证能关闭监听流,应在此处再 check 一下 handle.check(); return (0); } ``` -------------------------------- ### Generating and Installing acl_master RPM Package (CentOS) Source: https://acl-dev.cn/2023/06/10/using_master This section details how to generate an RPM package for acl_master on CentOS systems and subsequently install it. This simplifies deployment for users on CentOS environments. ```shell cd acl/packaging/ make PKG_NAME=acl_master # rpm -ivh acl-master-3.5.5-0.x86_64.rpm ``` -------------------------------- ### Linux Makefile Example for acl Library Source: https://acl-dev.cn/2019/06/30/faq A basic Makefile demonstrating how to compile and link an application using the acl library on a Linux platform. It specifies include paths and library linking order, including dependencies like lib_acl, lib_protocol, lib_acl_cpp, lib_fiber, and optional libraries like libz and libpthread. Note that spaces before lines in the code block should be converted to tabs when saving to a Makefile. ```makefile fiber: main.o g++ -o fiber main.o \ -L./lib_fiber/lib -lfiber_cpp \ -L./lib_acl_cpp/lib -l_acl_cpp \ -L./lib_protocol/lib -l_protocol \ -L./lib_acl/lib -l_acl \ -L./lib_fiber/lib -lfiber \ -lz -lpthread -ldl main.o: main.cpp g++ -O3 -Wall -c main.cpp -DLINUX2 \ -I./lib_acl/include \ -I./lib_acl_cpp/include \ -I./lib_fiber/cpp/include \ -I./lib_fiber/c/include ``` -------------------------------- ### Create and Start a Coroutine for Listening Network Connections Source: https://acl-dev.cn/2019/04/07/fiber This code snippet demonstrates how to create a coroutine (`CFiberListener`) to listen for incoming network connections on a specified address and port. It then starts this listener coroutine, enabling the application to accept client requests. ```cpp // 创建一个协程用来监听指定地址,接收客户端连接请求 m_fiberListen = new CFiberListener("127.0.0.1:8800"); // 启动监听协程 m_fiberListen->start(); ``` -------------------------------- ### C++协程WEB服务器实现 Source: https://acl-dev.cn/2016/07/06/fiber_web 使用 acl 协程库实现了一个高并发的 WEB 服务器。它包含一个主函数用于解析命令行参数、初始化 acl C++ 库,并创建一个服务监听协程。服务监听协程负责打开监听端口,并为每个接收到的客户端连接创建一个新的 HTTP 处理协程。HTTP 处理协程则通过 HttpServlet 类处理 HTTP 请求,并返回简单的 'hello world!' 响应。此实现依赖于 acl 库的协程和网络功能。 ```cpp #include "lib_acl.h" #include "fiber/lib_fiber.h" #include "acl_cpp/lib_acl.hpp" class http_servlet : public acl::HttpServlet { public: http_servlet(acl::socket_stream* stream, acl::session* session) : HttpServlet(stream, session) { } ~http_servlet(void) { } // override bool doGet(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { return doPost(req, res); } // override bool doPost(acl::HttpServletRequest&, acl::HttpServletResponse& res) { const char* buf = "hello world!"; size_t len = strlen(buf); res.setContentLength(len); res.setKeepAlive(true); // 发送 http 响应体 return res.write(buf, len) && res.write(NULL, 0); } }; #define STACK_SIZE 320000 // 指定协程堆栈大小(字节) static int __rw_timeout = 0; // 网络 IO 超时时间(秒) static void http_server(ACL_FIBER *, void *ctx) { acl::socket_stream *conn = (acl::socket_stream *) ctx; printf("start one http_server\r\n"); acl::memcache_session session("127.0.0.1:11211"); // 基于 ACL HTTP 模块的 Http 服务类 http_servlet servlet(conn, &session); servlet.setLocalCharset("gb2312"); // 循环处理客户端的 HTTP 请求 while (true) { // 调用 acl::HttpServlet 类中的方法,从而触发子类重载的 doPost/doGet 方法 if (servlet.doRun() == false) break; } printf("close one connection: %d, %s\r\n", conn->sock_handle(), acl::last_serror()); // 销毁客户端连接对象 delete conn; } static void fiber_accept(ACL_FIBER *, void *ctx) { const char* addr = (const char* ) ctx; acl::server_socket server; // 监听本机服务端口 if (server.open(addr) == false) { printf("open %s error\r\n", addr); exit (1); } else printf("open %s ok\r\n", addr); while (true) { // 等待接收外来 HTTP 客户端连接 acl::socket_stream* client = server.accept(); if (client == NULL) { printf("accept failed: %s\r\n", acl::last_serror()); break; } client->set_rw_timeout(__rw_timeout); printf("accept one: %d\r\n", client->sock_handle()); // 创建协程处理 HTTP 客户端连接请求 acl_fiber_create(http_server, client, STACK_SIZE); } exit (0); } static void usage(const char* procname) { printf("usage: %s -h [help] -s listen_addr -r rw_timeout\r\n", procname); } int main(int argc, char *argv[]) { acl::string addr("127.0.0.1:9001"); int ch; while ((ch = getopt(argc, argv, "hs:r:")) > 0) { switch (ch) { case 'h': usage(argv[0]); return 0; case 's': addr = optarg; break; case 'r': __rw_timeout = atoi(optarg); break; default: break; } } acl::acl_cpp_init(); acl::log::stdout_open(true); // 创建服务监听协程 acl_fiber_create(fiber_accept, addr.c_str(), STACK_SIZE); // 启动协程调度过程 acl_fiber_schedule(); return 0; } ```