acl
acl copied to clipboard
各平台的编译支持
源码好像还是utf8编码的好一些。好像很多跨平台支持的也都还是同一utf8编码的。
现在用cmake来组织工程是比较方便的了。比如安装可以通过 ExternalProject_Add 等方式来很方便的构建一个新工程 快速添加第三方库。
还有一些代码风格 在新版的c标准下不兼容 需要指定为c99的问题。这样有助于推广。 建议这部分列一个规范出来 然后一点点开源兼容的更改也好。 谢谢作者的贡献。希望项目越来越好
曾经我用工具将代码全转成utf8,但却无法在vs上正常显示,除非是每个文件里添加BOM头,所以目前只能暂保留GBK编码,最好的解决方案是全用英文,但这个翻译量太大了; 关于在UNIX Like 平台上编译Acl工程,不仅提供了Makefile方式,还提供了 cmake, xmke 的编译方式,另外在 Windows 上提供了 VS 的工程文件,在 MacOS 上提供了 Xcode 工程文件,针对 Android 还提供了 AS 相关的编译方式; 至于代码风格,最早是严格的标准C,后来才加入了c99的风格,不过大部分编译器是可以过的,如果需要的话,也可以加上c99编译开关。 最后也非常感谢您的关注,提供更多的建议,从而有利于Acl项目的健康发展。 非常感谢。 ---zsx
多谢大佬的回复,好快!
目前我在Linux中编译成功了。也和一些其他库做了性能比较。快又稳定。赞。 但是在mac平台遇到了麻烦。mac平台里的Xcode好像是为了iphone的设置。没有mac平台的。然后我也尝试过各个在cmake里添加c99 之类的。但是还是比较多报错。也试过直接mark。也是跑不通。另外之前用别的开源库的时候。大多数都是在cmake里做到统一。可以执行多个平台。然后win端也是用cmake生成vs工程。我想在mac也做性能测试下。
关于编码的讨论,“除非是每个文件里添加BOM头”这个方式是有什么不好的么,或者现在借助chatgpt可以快速翻译下。或者是正则分离直接把中文提取成api文档。
个人的一些做法和想法,仅供参考。我对C++的使用不多。但是最近为了性能就上了C++。个人觉得golang,nodejs之类的包管理器的理念都很好。C++的我找了类似的包管理器,有很多种。但是我比较用下来最舒服的就是用cmake了。几乎可以在一个cmake里声明好所有的用到的第三方库。包括openssl zlib curl的等。虽然每次都要编译一次。但是这样可以和其他语言一样做到工程用到的库只会依赖工程内的文件。同时,也不会修改到所在系统的文件和环境。特别是有的库,比如都依赖openssl,但是都要求使用特定小版本号,但是还不一样 这就很操蛋了。cmake里可以通过ExternalProject_Add的方式添加第三方的子仓库。编译后就在自己的build目录下 结构很清爽干净。迁移工程只需要一个cmakelist文件 不需要再要求手动安装各类库。个人工作流里 三个平台都是在vscode里编码。都是用cmake。下面是一些举例
include(ExternalProject)
ExternalProject_Add(zlib
URL https://www.zlib.net/zlib-1.2.13.tar.gz
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/zlib
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/zlib
BUILD_COMMAND make -j$(nproc)
INSTALL_COMMAND make install
)
ExternalProject_Add(openssl
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/openssl
URL https://www.openssl.org/source/openssl-1.1.1t.tar.gz
URL_HASH SHA256=8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b
DEPENDS zlib
CONFIGURE_COMMAND <SOURCE_DIR>/config no-tests --prefix=<INSTALL_DIR> --with-zlib-include=${CMAKE_CURRENT_BINARY_DIR}/zlib/include --with-zlib-lib=${CMAKE_CURRENT_BINARY_DIR}/zlib/lib --prefix=${CMAKE_CURRENT_BINARY_DIR}/openssl
BUILD_COMMAND make -j$(nproc)
INSTALL_COMMAND make install
)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/openssl/include)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/zlib/include)
如果各个环境之间有依赖关系
add_custom_target(curl_target
COMMAND echo "curl is installed"
DEPENDS curl
)
add_dependencies(http_press_test_tool_curl curl_target)
使用的时候
target_link_libraries(test PRIVATE -static-libstdc++ Threads::Threads ${CMAKE_CURRENT_BINARY_DIR}/curl/lib/libcurl.a ${CMAKE_CURRENT_BINARY_DIR}/openssl/lib/libssl.a ${CMAKE_CURRENT_BINARY_DIR}/openssl/lib/libcrypto.a
目前我使用acl工程的方式
project(test)
include(ExternalProject)
ExternalProject_Add(acl
URL https://github.com/acl-dev/acl/archive/v3.6.1-2/acl-3.6.1-2.tar.gz
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/acl
CMAKE_ARGS -DCMAKE_C_FLAGS_RELEASE=-O3 # -DACL_PREPARE_COMPILE=false
BUILD_COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl && make -j$(nproc) CFLAGS=${CMAKE_C_FLAGS} CFLAGS="${CMAKE_C_FLAGS} -Wno-strict-prototypes -Wno-unused-but-set-variable)"
INSTALL_COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl && make install CFLAGS=${CMAKE_C_FLAGS} CFLAGS="${CMAKE_C_FLAGS} -Wno-strict-prototypes -Wno-unused-but-set-variable)"
)
add_custom_target(acl_dep
COMMAND echo "acl is installed"
DEPENDS acl
)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/include)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/lib_acl/include)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/lib_acl_cpp/include)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/lib_protocol/include)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/dist/include)
这里的头文件确实比较分散。而且不同版本之间会有点混淆。如果我是C++用户,可能我最后只想include一个就好了。


如果更进一步。可以在cmake脚步的最初直接检测系统类型,直接用各个系统的命令安装对应的包管理比如mac的brew win的choco ,再安装cmake g++等库。就可以做到一个脚步搞定所有安装了。当然也可以考虑用docker。
谢谢作者的无私分享。
还有一个问题。大佬考虑增加设置http代理功能么。我看说明里是有实现的。但是只是在c里面实现的么。acl::http_request里好像没有实现。另外在lib_protocol也有实现。但是好像不是类似curl里面的 -x 选项的那种代理。
http_request_pool 能够在这个请求池里实现http代理么。 acl/lib_acl_cpp/samples/http_request_pool/main.cpp
在这里类里 实现了线程池 链接池。但是好像没办法设置代理。另外接收数据的buf 的写法是 char buf[8192];。如何用acl的可变长的buf来接收数据,或者是用acl::string来接收呢。 http_request(socket_stream* client, int conn_timeout = 60, bool unzip = true, bool stream_fixed = true);这里的stream_fixed这个需要改为固定的么。 我的需求大概是用连接池定时大量请求URL。并且使用代理获取。接收数据的buff也做对象池避免重复创建。每次接收到内容后,返回httpcode和respone内容给一个外部传入的回调处理。URL数组都处理完了后。也有一个总回调返回总耗时,统计失败个数,以此为依据调整并发量或者维持并发。
多谢大佬的回复,好快!
目前我在Linux中编译成功了。也和一些其他库做了性能比较。快又稳定。赞。 但是在mac平台遇到了麻烦。mac平台里的Xcode好像是为了iphone的设置。没有mac平台的。然后我也尝试过各个在cmake里添加c99 之类的。但是还是比较多报错。也试过直接mark。也是跑不通。另外之前用别的开源库的时候。大多数都是在cmake里做到统一。可以执行多个平台。然后win端也是用cmake生成vs工程。我想在mac也做性能测试下。
关于编码的讨论,“除非是每个文件里添加BOM头”这个方式是有什么不好的么,或者现在借助chatgpt可以快速翻译下。或者是正则分离直接把中文提取成api文档。
个人的一些做法和想法,仅供参考。我对C++的使用不多。但是最近为了性能就上了C++。个人觉得golang,nodejs之类的包管理器的理念都很好。C++的我找了类似的包管理器,有很多种。但是我比较用下来最舒服的就是用cmake了。几乎可以在一个cmake里声明好所有的用到的第三方库。包括openssl zlib curl的等。虽然每次都要编译一次。但是这样可以和其他语言一样做到工程用到的库只会依赖工程内的文件。同时,也不会修改到所在系统的文件和环境。特别是有的库,比如都依赖openssl,但是都要求使用特定小版本号,但是还不一样 这就很操蛋了。cmake里可以通过ExternalProject_Add的方式添加第三方的子仓库。编译后就在自己的build目录下 结构很清爽干净。迁移工程只需要一个cmakelist文件 不需要再要求手动安装各类库。个人工作流里 三个平台都是在vscode里编码。都是用cmake。下面是一些举例
include(ExternalProject) ExternalProject_Add(zlib URL https://www.zlib.net/zlib-1.2.13.tar.gz PREFIX ${CMAKE_CURRENT_BINARY_DIR}/zlib CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/zlib BUILD_COMMAND make -j$(nproc) INSTALL_COMMAND make install ) ExternalProject_Add(openssl PREFIX ${CMAKE_CURRENT_BINARY_DIR}/openssl URL https://www.openssl.org/source/openssl-1.1.1t.tar.gz URL_HASH SHA256=8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b DEPENDS zlib CONFIGURE_COMMAND <SOURCE_DIR>/config no-tests --prefix=<INSTALL_DIR> --with-zlib-include=${CMAKE_CURRENT_BINARY_DIR}/zlib/include --with-zlib-lib=${CMAKE_CURRENT_BINARY_DIR}/zlib/lib --prefix=${CMAKE_CURRENT_BINARY_DIR}/openssl BUILD_COMMAND make -j$(nproc) INSTALL_COMMAND make install ) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/openssl/include) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/zlib/include)
如果各个环境之间有依赖关系
add_custom_target(curl_target COMMAND echo "curl is installed" DEPENDS curl ) add_dependencies(http_press_test_tool_curl curl_target)
使用的时候
target_link_libraries(test PRIVATE -static-libstdc++ Threads::Threads ${CMAKE_CURRENT_BINARY_DIR}/curl/lib/libcurl.a ${CMAKE_CURRENT_BINARY_DIR}/openssl/lib/libssl.a ${CMAKE_CURRENT_BINARY_DIR}/openssl/lib/libcrypto.a
目前我使用acl工程的方式
project(test) include(ExternalProject) ExternalProject_Add(acl URL https://github.com/acl-dev/acl/archive/v3.6.1-2/acl-3.6.1-2.tar.gz PREFIX ${CMAKE_CURRENT_BINARY_DIR}/acl CMAKE_ARGS -DCMAKE_C_FLAGS_RELEASE=-O3 # -DACL_PREPARE_COMPILE=false BUILD_COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl && make -j$(nproc) CFLAGS=${CMAKE_C_FLAGS} CFLAGS="${CMAKE_C_FLAGS} -Wno-strict-prototypes -Wno-unused-but-set-variable)" INSTALL_COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl && make install CFLAGS=${CMAKE_C_FLAGS} CFLAGS="${CMAKE_C_FLAGS} -Wno-strict-prototypes -Wno-unused-but-set-variable)" ) add_custom_target(acl_dep COMMAND echo "acl is installed" DEPENDS acl ) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/include) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/lib_acl/include) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/lib_acl_cpp/include) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/lib_protocol/include) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/acl/src/acl/dist/include)
这里的头文件确实比较分散。而且不同版本之间会有点混淆。如果我是C++用户,可能我最后只想include一个就好了。
像目前的一些这种写法接入后效果比较好的结果就是如图中一样。每个依赖库的目录结构安装成功后变成这样。就可以自定义安装目录,又不依赖系统环境了。像acl目前的脚步安装后是这样
可能还有一些脚本里的设置需要调整。
如果更进一步。可以在cmake脚步的最初直接检测系统类型,直接用各个系统的命令安装对应的包管理比如mac的brew win的choco ,再安装cmake g++等库。就可以做到一个脚步搞定所有安装了。当然也可以考虑用docker。
谢谢作者的无私分享。
Acl 里的 Xcode 工程的设置缺省情况下确实是面向 iOS的,主要是因为平时工作的需要,你可以稍微修改一下工程设置改成适配 MacOS的,不过一般在Unix like 类的平台,可以直接使用 make 或 cmak 编译更方便些。 Acl库的一个设计目标就是尽量减少对第三方库的依赖,即使有依赖,也不希望给不使用这些功能的用户造成编译和使用上的障碍;比如 Acl 库封装了常见的数据库(如 Mysql, Sqlite, Postgresql)、OpenSSL、MbedTLS,但很多人在使用Acl库时并不需要这些第三方库的功能,如果强行要求这些用户去下载编译这些第三方库对他们而言将会是十分痛苦的,为减少这些痛苦过程,Acl库采用动态加载所依赖第三方库的方式去集成这些依赖库,这种动态加载方式对那些需要这些功能的用户而言也不会造成使用上的障碍(因为他们既然想要用诸如数据库或SSL功能,那么他应该是熟悉这些库的,而通过Acl 的二次封装,可以使他们使用这些功能更为简单易用,避免出错)。 最少依赖,最大兼容,分层模块化及安全稳定性一直是Acl的设计目标,至于那些语言的或工具的高级特性,Acl库也是保持尽量的谨慎。这样才可能应对复杂的真实工程环境(比如我经常需要在CentOS5, 6, 7, 8, Ubuntu 或 AS, iOS, Windows 等平台做一些实际的应用)。 在Acl库中,lib_acl 是最基础的库(C实现),然后 lib_protocol 是一些网络协议库(C实现),而 lib_acl_cpp则封装了lib_acl和lib_protocol的 C++ 库,同时增加了更多的面向应用实践的功能模块,如果你只是需要 c++功能,则头文件中仅需包含 lib_acl_cpp/include/acl_cpp/lib_acl.hpp 即可,其它的头文件均无需包含(这是因为在lib_acl_cpp c++ 库中都隐含了对于 lib_acl 及 lib_protocol 头文件的依赖);另外,Acl库中还有一个独立的网络协程库 lib_fiber(C实现)及 lib_fiber_cpp(用C++封装了 lib_fiber, lib_acl, lib_acl_cpp),而 lib_fiber 是完全独立于 lib_acl 等几个库的,使用者可以根据需求自行包含。
还有一个问题。大佬考虑增加设置http代理功能么。我看说明里是有实现的。但是只是在c里面实现的么。acl::http_request里好像没有实现。另外在lib_protocol也有实现。但是好像不是类似curl里面的 -x 选项的那种代理。
http_request_pool 能够在这个请求池里实现http代理么。 acl/lib_acl_cpp/samples/http_request_pool/main.cpp
在这里类里 实现了线程池 链接池。但是好像没办法设置代理。另外接收数据的buf 的写法是 char buf[8192];。如何用acl的可变长的buf来接收数据,或者是用acl::string来接收呢。 http_request(socket_stream* client, int conn_timeout = 60, bool unzip = true, bool stream_fixed = true);这里的stream_fixed这个需要改为固定的么。 我的需求大概是用连接池定时大量请求URL。并且使用代理获取。接收数据的buff也做对象池避免重复创建。每次接收到内容后,返回httpcode和respone内容给一个外部传入的回调处理。URL数组都处理完了后。也有一个总回调返回总耗时,统计失败个数,以此为依据调整并发量或者维持并发。
关于HTTP代理,可以参考其中的例子:https://github.com/acl-dev/acl/tree/master/app/wizard_demo/httpd_proxy 。 acl::http_request 类提供了多种读数据的方法,比如:get_body(json&,...), get_body(xml&,...) 更多的方法可参考头文件;关于该类构造中的 stream_fixed 参数含义,建议参考一下头文件说明。
还有一个问题。大佬考虑增加设置http代理功能么。我看说明里是有实现的。但是只是在c里面实现的么。acl::http_request里好像没有实现。另外在lib_protocol也有实现。但是好像不是类似curl里面的 -x 选项的那种代理。 http_request_pool 能够在这个请求池里实现http代理么。 acl/lib_acl_cpp/samples/http_request_pool/main.cpp 在这里类里 实现了线程池 链接池。但是好像没办法设置代理。另外接收数据的buf 的写法是 char buf[8192];。如何用acl的可变长的buf来接收数据,或者是用acl::string来接收呢。 http_request(socket_stream* client, int conn_timeout = 60, bool unzip = true, bool stream_fixed = true);这里的stream_fixed这个需要改为固定的么。 我的需求大概是用连接池定时大量请求URL。并且使用代理获取。接收数据的buff也做对象池避免重复创建。每次接收到内容后,返回httpcode和respone内容给一个外部传入的回调处理。URL数组都处理完了后。也有一个总回调返回总耗时,统计失败个数,以此为依据调整并发量或者维持并发。
关于HTTP代理,可以参考其中的例子:https://github.com/acl-dev/acl/tree/master/app/wizard_demo/httpd_proxy 。 acl::http_request 类提供了多种读数据的方法,比如:get_body(json&,...), get_body(xml&,...) 更多的方法可参考头文件;关于该类构造中的 stream_fixed 参数含义,建议参考一下头文件说明。
HTTP代理 例子是全局http代理的做法么。老实说我对这个不熟悉,一开始也是看到这个类的了。没看明白。我的需求可能是每个httpclient都需要不同的proxy。老哥能稍微说下proxy相关原理么。或者有一些文章链接。
你可以直接使用 acl::http_request 类完成你的需求,在构造时传入代理服务器的地址(如:xxx.xxx.xxx.xxx:port),然后就以构建 HTTP 请求直接向代理服务器发送请求了。
老哥 。 例如这个curl命令 curl www.baidu.com -x http://58.246.58.150:9002 。是通过http代理 访问百度数据。这样如果短期内请求太多。也只是代理被百度限流。 如何用 acl::http_request 完成此类需求 ,麻烦举个小例子的伪代码
你可以直接使用 acl::http_request 类完成你的需求,在构造时传入代理服务器的地址(如:xxx.xxx.xxx.xxx:port),然后就以构建 HTTP 请求直接向代理服务器发送请求了。
我看相关的知识点的解释好像也是说。是要先发给代理服务器 然后代理服务器会再发给目标服务器。就是还没弄清楚是在哪里把这两个值传递给代理服务器的。是不是我在httphead指定目标服务器 在request指定代理服务器。set_url这个接口是用来设置哪个参数概念的
你可以直接使用 acl::http_request 类完成你的需求,在构造时传入代理服务器的地址(如:xxx.xxx.xxx.xxx:port),然后就以构建 HTTP 请求直接向代理服务器发送请求了。
在弱cpu的云服务器上测试。acl库的表现好太多了。用curl好像cpu波动和速度都慢,当然也是我没做任何优化,同一机器上表现相差很多。和libhv写的wrk。同比测试好太多了。按照那个项目的描述应该也是不差的才对。该做的优化点都做了。github现在提供了小型云docker一样的环境。上面的网速很快 就是核心数少 。我横向测试了好几个。ack写的大概每秒可以到2000个请求百度。其他的100到1000不等。
老哥 。 例如这个curl命令 curl www.baidu.com -x http://58.246.58.150:9002 。是通过http代理 访问百度数据。这样如果短期内请求太多。也只是代理被百度限流。 如何用 acl::http_request 完成此类需求 ,麻烦举个小例子的伪代码
你可以直接使用 acl::http_request 类完成你的需求,在构造时传入代理服务器的地址(如:xxx.xxx.xxx.xxx:port),然后就以构建 HTTP 请求直接向代理服务器发送请求了。
我看相关的知识点的解释好像也是说。是要先发给代理服务器 然后代理服务器会再发给目标服务器。就是还没弄清楚是在哪里把这两个值传递给代理服务器的。是不是我在httphead指定目标服务器 在request指定代理服务器。set_url这个接口是用来设置哪个参数概念的
在http_request的构造函数里,填写代理服务器的地址,然后再对http_request对象设置http请求参数,这样每个请求都会通过代理发出至目标http服务器。 比如下面的例子:
const char* proxy_addr="myproxy.com:80";
acl::http_request req(proxy_addr);
acl::http_header& hdr = req.request_header();
hdr.set_url("/").set_host("www.baidu.com").set_keep_alive(true);
if (req.request(NULL, 0)) {
acl::string body;
if (req.get_body(body)) {
printf("get body length:%zd, data: %s\r\n", body.size(), body.c_str());
} else {
printf("get body error\r\n");
}
} else {
printf("send request error\r\n");
}
老哥 。 例如这个curl命令 curl www.baidu.com -x http://58.246.58.150:9002 。是通过http代理 访问百度数据。这样如果短期内请求太多。也只是代理被百度限流。 如何用 acl::http_request 完成此类需求 ,麻烦举个小例子的伪代码
你可以直接使用 acl::http_request 类完成你的需求,在构造时传入代理服务器的地址(如:xxx.xxx.xxx.xxx:port),然后就以构建 HTTP 请求直接向代理服务器发送请求了。
我看相关的知识点的解释好像也是说。是要先发给代理服务器 然后代理服务器会再发给目标服务器。就是还没弄清楚是在哪里把这两个值传递给代理服务器的。是不是我在httphead指定目标服务器 在request指定代理服务器。set_url这个接口是用来设置哪个参数概念的
在http_request的构造函数里,填写代理服务器的地址,然后再对http_request对象设置http请求参数,这样每个请求都会通过代理发出至目标http服务器。 比如下面的例子:
const char* proxy_addr="myproxy.com:80"; acl::http_request req(proxy_addr); acl::http_header& hdr = req.request_header(); hdr.set_url("/").set_host("www.baidu.com").set_keep_alive(true); if (req.request(NULL, 0)) { acl::string body; if (req.get_body(body)) { printf("get body length:%zd, data: %s\r\n", body.size(), body.c_str()); } else { printf("get body error\r\n"); } } else { printf("send request error\r\n"); }
真的很感谢老哥的回复。很好很快很无私。十分感谢。我再试试