1 / 64

ACL 库常用 API 使用介绍

ACL 库常用 API 使用介绍. 2011.10. 目录. 常用数据结构 网络编程 数据库编程 XML 解析库 JSON 解析库 HTTP 协议库 服务器编程. 常用数据结构. 动态数组 队列 堆栈 双向环 哈希表 二分块查找 二叉树 平衡二叉树 快速匹配树 通用遍历器. 动态数组(一) --- 常用数据结构. 结构定义: ACL_ARRAY 主要函数 : 数组创建: ACL_ARRAY* acl_array_create(int) 数组添加: int acl_array_append(ACL_ARRAY*, void*)

jason
Download Presentation

ACL 库常用 API 使用介绍

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ACL库常用API使用介绍 2011.10

  2. 目录 • 常用数据结构 • 网络编程 • 数据库编程 • XML解析库 • JSON解析库 • HTTP协议库 • 服务器编程

  3. 常用数据结构 • 动态数组 • 队列 • 堆栈 • 双向环 • 哈希表 • 二分块查找 • 二叉树 • 平衡二叉树 • 快速匹配树 • 通用遍历器

  4. 动态数组(一)---常用数据结构 • 结构定义:ACL_ARRAY • 主要函数: • 数组创建:ACL_ARRAY* acl_array_create(int) • 数组添加:int acl_array_append(ACL_ARRAY*, void*) • 数组访问:acl_array_index(ACL_ARRAY*, int) • 数组释放:acl_array_free(ACL_ARRAY*, void (*)(void*)) • 举例: • ACL_ARRAY *a = acl_array_create(10); // 创建动态数组 • int i; • char *buf; • for (i = 0; i < 20; i++) { // 循环添加动态对象 • buf = malloc(256); • snprintf(buf, 256, “hello: %d”, i); • acl_array_append(a, buf); • } • for (i = 0; i < 20; i++) { // 查找定位 • char *ptr = (char*) acl_array_index(a, i); // 根据数组下标取出元素 • printf(“%s\n”, ptr); • } • acl_array_free(a, free); // 释放动态数组及动态对象 • 参考: lib_acl/include/stdlib/acl_array.h

  5. 字符串动态数组(二)---常用数据结构 • 结构定义:ACL_ARGV • 主要函数 • 创建:方法一,acl_argv_alloc(int),方法二,acl_argv_split(string) • 添加:acl_argv_add(ACL_ARGV*, string, …, NULL) • 访问:acl_argv_index(ACL_ARGV*, int) • 销毁:acl_argv_free(ACL_ARGV*) • 举例 • ACL_ARGV *a = acl_argv_split(“hello world, you are welcome; Bye!”, “ ,;!”); // 分隔字符串,并创建字符串数组 • int i, size; • acl_argv_add(a, “How”, “old”, “are”, “you”, NULL); // 向动态数组中添加新的字符串 • size = acl_argv_size(a); // 数组中元素个数 • for (i = 0; i < size; i++) { • char *ptr = acl_argv_index(a, i); // 取出对应下标的字符串 • printf(“%s\n”, ptr); • } • acl_argv_free(a); // 释放字符串数组 • 参考: lib_acl/include/stdlib/acl_argv.h

  6. 队列---常用数据结构 • 结构定义:ACL_FIFO • 主要函数 • 创建:acl_fifo_new() • 添加:向队列尾部添加,acl_fifo_push_back(ACL_FIFO*, void*) • 向队列头部添加,acl_fifo_push_front(ACL_FIFO*, void*) • 访问:访问队列头, (void*) acl_fifo_head(ACL_FIFO*);访问队列尾, (void*) acl_fifo_tail(ACL_FIFO*) • 弹出:从尾部弹出对象,(void*) acl_fifo_pop_front(ACL_FIFO*) ,与 acl_fifo_push_back 组合为先进先出方式 • 从头部弹出对象,(void*) acl_fifo_pop_back(ACL_FIFO*),与 acl_fifo_push_front 组合为后进先出方式 • 销毁:acl_fifo_free(ACL_FIFO*, void (*free_fn)(void*)) • 举例 • ACL_FIFO *fifo = acl_fifo_new(); // 创建队列 • char *buf, *ptr; • int i; • for (i = 0; i < size; i++) { • char *buf = malloc(256); • snprintf(buf, 256, “hello: %d”, i); • acl_fifo_push_back(fifo, buf); // 向队列中添加元素 • } • while ((ptr = (char*) acl_fifo_pop_front(fifo)) != NULL) { • printf(“>>ptr: %s\n”, ptr); • free(ptr); • } • acl_fifo_free(fifo, NULL); // 因为调用了 acl_fifo_pop_xxx 函数,已经将对象从队列中清除,所以不再需要输入 • // 用来释放队列中元素的回调函数 • 参考: lib_acl/include/stdlib/acl_fifo.h

  7. 双向环---常用数据结构 • 结构定义:ACL_RING • 主要函数 • 初始化:acl_ring_init(ACL_RING*) • 尾部添加:acl_ring_append(ACL_RING*, ACL_RING*) • 删除链结点:acl_ring_detach(ACL_RING*) • 弹出结点:(ACL_RING*) acl_ring_pop_head(ACL_RING*) • 结点转用户对象:acl_ring_to_appl(ACL_RING*, {app_type}, {ring_member}) • 遍历访问: acl_ring_foreach(ACL_RING_ITERATOR*, ACL_RING*) • 举例 • typedef struct DUMMY { • char buf[256]; • int n; • ACL_RING entry; • } DUMMY; • struct DUMMY dummy1, dummy2; • ACL_RING_ITERATOR iter; • ACL_RING header; • … • acl_ring_init(&header); // 初始化双向环头对象 • acl_ring_append(&header, &dummy1.entry); // 添加结点 • acl_ring_append(&header, &dummy2.entry); // 添加结点 • acl_ring_foreach(iter, &header) { // 遍历 • ACL_RING *item = iter.ptr; • struct DUMMY *dm = acl_ring_to_appl(item, DUMMY, entry); // 转换为用户类型 • … • } • acl_ring_detach(&dummy1.entry); // 将 dummy1 结点从双向环中删除掉 • 参考: lib_acl/include/stdlib/acl_ring.h

  8. 哈希表---常用数据结构 • 结构定义:ACL_HTABLE • 主要函数: • 创建:(ACL_HTABLE*) acl_htable_create(int init_size, unsigned int flag) • 添加:acl_htable_enter(ACL_HTABLE*, const char *key, void* obj) • 查询:(void*) acl_htable_find(ACL_HTABLE*, const char *key) • 销毁:acl_htable_free(ACL_HTABLE*, void (*free_fn)(void*)) • 举例: • ACL_HTABLE *table = acl_htable_create(10, 0); // 创建哈希表 • int i; • char *buf, key[256]; • for (i = 0; i < 20; i++) { // 循环添加动态对象 • snprintf(key, sizeof(key), “hello: %d”, i); • buf = malloc(256); • snprintf(buf, 256, “hello: %d”, i); • acl_htable_enter(table, key, buf); // 向哈希表中添加元素 • } • for (i = 0; i < 20; i++) { // 查找 • snprintf(key, sizeof(key), “hello: %d”, i); • buf = (char*) acl_htable_find(table, key); // 从哈希表中查找元素 • if (buf != NULL) • printf(“%s\n”, buf); • } • acl_htable_free(table, free); // 释放哈希表及动态成员变量 • 参考: lib_acl/include/stdlib/acl_htable.h

  9. 二分块查找---常用数据结构 • 结构定义:ACL_DLINK,ACL_DITEM • 主要函数: • 创建:(ACL_DLINK*) acl_dlink_create(int init_size) • 添加:acl_htable_enter(ACL_HTABLE*, const char *key, void* obj) • 查询:(void*) acl_htable_find(ACL_HTABLE*, const char *key) • 销毁:acl_htable_free(ACL_HTABLE*, void (*free_fn)(void*)) • 举例: • ACL_DLINK *dlink = acl_dlink_create(10); // 创建二分块查找对象 • // 添加多个整数区间 • acl_dlink_insert(dlink, 100, 100); • acl_dlink_insert(dlink, 85, 99); • acl_dlink_insert(dlink, 83, 85); • acl_dlink_insert(dlink, 1,50); • acl_dlink_insert(dlink, 50, 60); • acl_dlink_insert(dlink, 59, 80); • // 内部的排列应该为:1-80, 83-99, 100-100 • // 查找某个整数是否在 dlink 的整数区间内 • if (acl_dlink_lookup(dlink, 49) != NULL) • printf(“Yes, 49 in dlink range\r\n”); • acl_dlink_free(dlink); // 销毁过程 • 参考: lib_acl/include/stdlib/acl_dlink.h

  10. 平衡二叉树---常用数据结构 • 结构定义:avl_tree_t, avl_node_t, avl_index_t • 主要函数 • 创建:avl_create(avl_tree_t*, int (*cmp_fn)(const void*, const void*), sizeof(USER_STRUCT), offsetof(USER_STRUCT, node_member); • 添加:avl_add(avl_tree_t*, USER_STRUCT) • 查找:(USRE_STRUCT*) avl_find(avl_tree_t*, USER_STRUCT*, avl_index_t) • 删除:avl_remove(avl_tree_t*, USER_STRUCT*) • 销毁:avl_destroy(avl_tree_t*) • 举例 • typedef struct DUMMY { • char buf[256]; • int n; • avl_node_t entry; // 平衡二叉树结点 • } DUMMY; • static int cmp_func(const void* n1, const void* n2) // 平衡二叉树的比较函数 • { • DUMMY *d1 = (DUMMY*) n1, *d2 = (DUMMY*) n2; • Return (d1->n – d2->n); • } • … • struct DUMMY dummy1, dummy2, dummy, *dummy_ptr; • avl_tree_t tree; // 平衡二叉树对象 • avl_create(&tree, cmp_func, sizeof(DUMMY), offsetof(DUMMY, entry); // 创建平衡二叉树 • … • avl_add(&tree, &dummy1); // 添加结点 • avl_add(&tree, &dummy2); // 添加结点 • dummy.n = 1; • dummy_ptr = (DUMMY*) avl_find(&tree, &dummy); // 查找结点 • dummy.n = dummy1.n; • avl_remove(&tree, &dummy); // 删除结点 • dummy.n = dummy2.n; • avl_remove(&tree, &dummy); // 删除结点 • avl_destroy(&tree); // 销毁平衡二叉树对象 • 参考: lib_acl/include/stdlib/avl.h

  11. 通用遍历器---常用数据结构 • 结构定义:ACL_ITER • 使用方法:变量声明 正向遍历 逆向遍历 • ACL_ITER iter; acl_foreach(iter, container) { acl_foreach_reverse(iter, container) { void* ptr = iter.data; void* ptr = iter.data; … … • } } • 符合ACL_ITER要求的容器: • 数据结构部分:ACL_ARRAY, ACL_ARGV, ACL_FIFO, ACL_STACK, ACL_DLINK, ACL_HTABLE, ACL_BINHASH • 网络部分:ACL_DNS_DB, ACL_IFCONF • 数据库部分:ACL_SQL_RES, ZDB_STORE • 解析器:ACL_XML/ACL_XML_NODE, ACL_JSON/ACL_JSON_NODE • 举例: • typedef struct DUMMY { • char buf[256]; • int n; • } DUMMY; • ACL_ARRAY *a = acl_array_create(10); // 创建动态数组 • ACL_HTABLE *t = acl_htable_create(10, 0); // 创建哈希表 • DUMMY dummy1, dummy2, *dummy_ptr; • ACL_ITER iter; // 遍历对象 • acl_array_append(a, &dummy1); acl_array_append(a, &dummy2); // 添加结点至动态数组中 • acl_htable_enter(t, “key1”, &dummy1); acl_htable_enter(t, “key2”, &dummy2); // 添加结点至哈希表中 • acl_foreach(iter, a) { // 遍历动态数组中的所有元素 • dummy_ptr = (DUMMY*) iter.data; • printf(“%s\n”, dummy_ptr->buf); • } • acl_foreach(iter, t) { // 遍历哈希表中的所有元素 • dummy_ptr = (DUMMY*) iter.data; • printf(“%s\n”, dummy_ptr->buf); • } • acl_array_free(a, NULL); // 销毁动态数组 • acl_htable_free(t, NULL); // 销毁哈希表 • 参考: lib_acl/include/stdlib/acl_iterator.h

  12. 网络编程 • TCP/IP 协议基础 • 较为底层的网络编程 • TCP连接控制 • 较为高层的网络编程 • 网络流读写 • 域名解析 • 网络编程杂项 • 异步非阻塞网络编程

  13. TCP/IP 协议分层---TCP/IP协议基础

  14. 数据封装---TCP/IP协议基础

  15. 较为底层的网络编程 • 1)服务端 • 网络套接口监听:ACL_SOCKET acl_inet_listen(const char* addr, int backlog, int block_mode); • 接收客户端连接:ACL_SOCKET acl_inet_accept(ACL_SOCKET listenfd); • ACL_SOCKET acl_sane_accept(ACL_SOCKET listenfd, struct sockaddr *sa, socklen_t *len); • 示例: • const char* addr=“127.0.0.1:8080”; • ACL_SOCKET listenfd = acl_inet_listen(addr, 128, ACL_BLOCKING) /* 监听 */, clientfd; • acl_assert(listenfd); • while (1) { • clientfd = acl_inet_accept(listenfd); // 等待客户端连接 • if (clientfd == ACL_SOCKET_INVALID) • continue; • … • acl_socket_close(clientfd); // 关闭客户端连接 • } • 2)客户端 • 连接TCP服务器:ACL_SOCKET acl_inet_connect(const char* addr, int block_mode, int timeout); • 连接UNIX域服务器:ACL_SOCKET acl_unix_connect(const char* addr, int block_mode, int timeout); • int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr* sa, socklen_t len); • 示例: • const char* addr = “127.0.0.1:8080”; • ACL_COCKET clientfd = acl_inet_connect(addr, ACL_BLOCKING, 60); // 连接服务器 • if (clientfd != ACL_SOCKET_INVALID) { • … • acl_socket_close(clientfd); // 关闭连接 • } • 参考:lib_acl/include/net, acl_listen.h, acl_connect.h

  16. TCP连接控制 • 1)设置延迟发送开关(IPPROTO_TCP/TCP_NODELAY): • acl_tcp_nodelay(ACL_SOCKET fd, int onoff); • 2)设置数据可读接收(IPPROTO_TCP/ TCP_DEFER_ACCEPT): • void acl_tcp_defer_accept(ACL_SOCKET listenfd, int timeout); • 3)设置连接关闭属性(SOL_SOCKET/ SO_LINGER): • acl_tcp_so_linger(ACL_SOCKET fd, int onoff, int timeout); • 4)设置/获得套接口读缓冲区大小 • void acl_tcp_set_rcvbuf(ACL_SOCKET fd, int size); • int acl_tcp_get_rcvbuf(ACL_SOCKET fd); • 5)设置/获得套接口写缓冲区大小 • void acl_tcp_set_sndbuf(ACL_SOCKET fd, int size); • int acl_tcp_get_sndbuf(ACL_SOCKET fd); • 6)获得远程连接的地址 • int acl_getpeername(ACL_SOCKET sockfd, char *buf, size_t bsize); • 7)获得本地连接的地址 • int acl_getsockname(ACL_SOCKET sockfd, char *buf, size_t bsize); • 参考:lib_acl/include/net/acl_tcp_ctl.h

  17. 较为高层的网络编程 • 1)服务端: • 监听本地地址:ACL_VSTREAM *acl_vstream_listen(const char *addr, int qlen); • 接收远程连接:ACL_VSTREAM *acl_vstream_accept(ACL_VSTREAM *listen_stream, char *ipbuf, int bsize); • 示例: • const char* addr = “127.0.0.1:8080”; • ACL_VSTREAM* server = acl_vstream_listen(addr, 128) /* 服务器监听 */, *client; • acl_assert(server); • while (1) { • client = acl_vstream_accept(server, NULL, 0); // 等待客户端连接 • if (client == NULL) • continue; • do_something(client); • acl_vstream_close(client); // 关闭客户端连接 • } • 2)客户端: • 建立远程连接:ACL_VSTREAM *acl_vstream_connect(const char *addr, int block_mode, • int connect_timeout, int rw_timeout, int rw_bufsize); • 示例: • Const char* addr = “127.0.0.1:8080”; • ACL_VSTREAM* client = acl_vstream_connect(addr, ACL_BLOCKING, 60, 60, 8192); // 连接服务器 • If (client) { • do_something(client); • acl_vstream_close(client); // 关闭连接 • } • 参考: lib_acl/include/stdlib/acl_vstream_net.h

  18. 网络流读写接口 • 1)按行读数据,不去掉末尾的\r\n (阻塞方式) • int acl_vstream_gets(ACL_VSTREAM *stream, void *buf, size_t maxlen); • 2)按行读数据,去掉末尾的\r\n (阻塞方式) • int acl_vstream_gets_nonl(ACL_VSTREAM *stream, void *buf, size_t maxlen); • 3)读取N个字节的数据(阻塞方式) • int acl_vstream_readn(ACL_VSTREAM *stream, char *buf, int size); • 4)一次性从流读操作, 返回实际读取的字节数 • Int acl_vstream_read(ACL_VSTREAM *stream, char *buf, int size); • 5)写入N个字节的数据(阻塞方式) • int acl_vstream_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen); • 6)一次性写入流操作, 返回实际写入的字节数 • int acl_vstream_write(ACL_VSTREAM *stream, const void *vptr, size_t dlen); • 7)以格式方式写入数据(阻塞方式) • int acl_vstream_fprintf(ACL_VSTREAM *stream, const char *fmt, ...); • int acl_vstream_vfprintf(ACL_VSTREAM *stream, const char *fmt, va_list ap); • 8)带缓冲方式的写入(阻塞方式) • int acl_vstream_buffed_fprintf(ACL_VSTREAM *stream, const char *fmt, ...); • int acl_vstream_buffed_vfprintf(ACL_VSTREAM *stream, const char *fmt, va_list ap); • int acl_vstream_buffed_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen); • 9)刷新写缓冲区里的数据(阻塞方式) • int acl_vstream_fflush(ACL_VSTREAM *stream); • 参考:lib_acl/include/stdlib/acl_vstream.h

  19. 网络流写示例 • static void do_write(ACL_VSTREAM* client) • { • char buf[8192]; • const char* data = “hello world!\r\n”), *ptr; • int ret, n; • ACL_VSTREAM_SET_RWTIMO(client, 60); // 设置IO读写超时时间 • n = (int) strlen(data); • // 写数据过程 ret = acl_vstream_fprintf(client, “hello world\r\n%s”, data); // 格式写入一行数据 • if (ret == ACL_VSTREAM_EOF) { • acl_msg_error(“fprintf to client error: %s”, acl_last_serror()); • return; • } • ret = acl_vstream_writen(client, data, n); // 写入定长数据,完全写成功或出错时才返回 • if (ret == ACL_VSTREAM_EOF) { // 表示出错,之后应该关闭 client 连接流 • acl_msg_error(“write to client error: %s”, acl_last_serror()); • return; • } • // acl_vstream_writen 等效于如下写过程 • ptr = data; • while (n > 0) { • ret = acl_vstream_write(client, ptr, n); • if (ret == ACL_VSTREAM_EOF) { • acl_msg_error(“write to client error: %s”, acl_last_serror()); • return; • } • n -= ret; } • } • 参考:lib_acl/include/stdlib/acl_vstream.h; samples/vstream

  20. 网络流读示例 • static void do_read(ACL_VSTREAM* client) • { • char buf[8192]; • int ret; • ACL_VSTREAM_SET_RWTIMO(client, 60); // 设置IO读写超时时间 • ret = acl_vstream_gets(client, buf, sizeof(buf)); // 读完整一行数据,尾部含\r\n或\n • if (ret == ACL_VSTREAM_EOF) { • acl_msg_error(“%s(%d), %s: gets error: %s”, __FILE__, __LINE__, __FUNCTION__, acl_last_serror()); return; • } • ret = acl_vstream_gets_nonl(client, buf, sizeof(buf)); // 读完整行数据,尾部不含\r\n 或\n • if (ret == ACL_VSTREAM_EOF) { • acl_msg_error(“%s(%d), %s: gets error: %s”, __FILE__, __LINE__, __FUNCTION__, acl_last_serror()); return; • } • ret = acl_vstream_readn(client, buf, sizeof(buf) – 1); // 读 8191 个字节 • if (ret == ACL_VSTREAM_EOF) { • acl_msg_error(“%s(%d), %s: readn error: %s”, __FILE__, __LINE__, acl_last_serror()); return; • } • ret = acl_vstream_read(client, buf, sizeof(buf) - 1); // 只要有数据可读或出错或超时都返回 • if (ret == ACL_VSTREAM_EOF) { • acl_msg_error(“%s(%d), %s: read error: %s”, • __FILE__, __LINE__, acl_last_serror()); return; • } • acl_msg_info(“read over now”); • } • 参考:lib_acl/include/stdlib/acl_vstream.h; samples/vstream

  21. 域名解析 • 1)通用域名解析函数:ACL_DNS_DB *acl_gethostbyname(const char *name, int *h_error); • 2)释放解析结果内存:void acl_netdb_free(ACL_DNS_DB *dns_db); • 示例: • const char* domain = “mail.51iker.com”; • int errnum; • ACL_DNS_DB* dns_db = acl_gethostbyname(domain, &errnum); // 解析域名 • if (dns_db == NULL) { • printf(“can’t get %s’ ip, error: %s\r\n”, domain, acl_netdb_strerror(errnum)); • } else { • ACL_ITER iter; • acl_foreach(iter, dns_db) { // 遍历域名解析结果 • const ACL_HOSTNAME* name = (const ACL_HOSTNAME*) iter.data; • printf(“ip: %s\n”, name->ip); • } • acl_netdb_free(dns_db); • } • 参考:lib_acl/include/net/acl_netdb.h

  22. 网络编程杂项 • 1)从流中获得套接字:ACL_SOCKET fd = ACL_VSTREAM_SOCK(ACL_VSTREAM*); • 2)从流中获得远程地址:const char* addr = ACL_VSTREAM_PEER(ACL_VSTREAM*); • 3)设置流的读写超时时间:ACL_VSTREAM_SET_RWTIMO(ACL_VSTREAM*, int); • 4)获得本机网卡地址列表: • 结构定义:ACL_IFCONF, ACL_IFADDR • 函数定义: • 获得本机网卡集合:ACL_IFCONF *acl_get_ifaddrs(void); • 释放结果:void acl_free_ifaddrs(ACL_IFCONF *ifconf); • 示例: • ACL_IFCONF* ifconf = acl_get_ifaddrs(); // 获得本机的所有网卡地址 • If (ifconf) { • ACL_ITER iter; • acl_foreach(iter, ifconf) { // 遍历网卡地址集 • const ACL_IFADDR* addr = (const ACL_IFADDR*) iter.data; • printf(“name: %s, ip: %s\n”, addr->name, addr->ip); • } • acl_free_ifaddrs(ifconf); // 释放内存 • } • 参考:lib_acl/include/stdlib/acl_vstream.h, lib_acl/include/net/acl_ifconf.h

  23. 异步通信框架---非阻塞网络编程 • 1)结构定义:ACL_AIO, ACL_ASTREAM • 2)主要函数: • 创建异步句柄:ACL_AIO *acl_aio_create(int event_mode); • ACL_AIO *acl_aio_create2(int event_mode, unsigned int nMsg); • event_mode: ACL_EVENT_SELECT, ACL_EVENT_POLL, • ACL_EVENT_KERNEL(epoll/devpool/kqueue/iocp), ACL_EVENT_WMSG(win32) • 异步循环:void acl_aio_loop(ACL_AIO *aio); • 释放异步句柄:void acl_aio_free(ACL_AIO *aio); • 创建异步通信流:ACL_ASTREAM *acl_aio_open(ACL_AIO *aio, ACL_VSTREAM *stream); • 异步IO完成后关闭异步流:void acl_aio_iocp_close(ACL_ASTREAM *astream); • 设置异步流的参数:void acl_aio_ctl(ACL_ASTREAM *astream, int name, ...); • 主动检查延迟关闭连接:void acl_aio_check(ACL_AIO *aio); • 设置持续读状态:void acl_aio_set_keep_read(ACL_AIO *aio, int onoff); • 设置异步定时器:acl_int64 acl_aio_request_timer(ACL_AIO *aio, • ACL_AIO_TIMER_FN timer_fn, void *context, acl_int64 idle_limit); • 取消异步定时器:acl_int64 acl_aio_cancel_timer(ACL_AIO *aio, • ACL_AIO_TIMER_FN timer_fn, void *context); • 参考:lib_acl/include/aio/acl_aio.h

  24. 服务端接口 ---非阻塞网络编程 • 设置异步监听流的回调函数: • 方法一: • static int __accept_callback(ACL_ASTREAM *client, void *context) • { • do_something(client, context); • return 0; • } • acl_aio_ctl(ACL_ASTREAM *, ACL_AIO_CTL_ACCEPT_FN, __accept_callback, ACL_AIO_CTL_CTX, xxx, ACL_AIO_CTL_END); • 方法二: • static int __listen_callback(ACL_ASTREAM *sstream, void *context) • { • ACL_ASTREAM* client; • ACL_VSTREAM* cstream = acl_vstream_accept(acl_aio_vstream(sstream)); // 接收客户端连接 • If (cstream == NULL) • return (0); client = acl_aio_open(acl_aio_handle(sstream), cstream); // 将客户端连接转为异步流 do_something(client, context); return 0; • } • acl_aio_ctl(ACL_ASTREAM *, ACL_AIO_CTL_LISTEN_FN, __listen_callback, ACL_AIO_CTL_CTX, xxx, ACL_AIO_CTL_END); • 示例: • ACL_AIO* aio = acl_aio_create(ACL_EVENT_KERNEL); // 创建本机支持的内核级异步事件引擎对象 • ACL_ASTREAM* sstream; • ACL_VSTREAM* server = acl_vstream_listen(“127.0.0.1:8080”, 128); // 监听 • acl_assert(server); • sstream = acl_aio_open(aio, server); // 将监听流转为异步流 • acl_aio_ctl(sstream, ACL_AIO_CTL_ACCEPT_FN, __accept_callback, ACL_AIO_CTL_END); // 设置异步服务流的回调函数 • while (1) { • acl_aio_loop(aio); // 异步事件循环 • }

  25. 客户端接口—读操作 ---非阻塞网络编程 • 回调函数类型:typedef int (*ACL_AIO_READ_FN)(ACL_ASTREAM *astream, void *context, char *data, int dlen); • 主要函数: • 1)设置读回调函数(可以针对一个客户端同时添加多个回调函数): • void acl_aio_add_read_hook(ACL_ASTREAM *astream, ACL_AIO_READ_FN callback, void *ctx); • 2)删除读回调函数: • void acl_aio_del_read_hook(ACL_ASTREAM *astream, ACL_AIO_READ_FN callback, void *ctx); • 3)异步读一行数据: • void acl_aio_gets(ACL_ASTREAM *astream); • void acl_aio_gets_nonl(ACL_ASTREAM *astream); • 4)异步读规定字节数据: • void acl_aio_readn(ACL_ASTREAM *astream, int count); • 5)读任意长度的数据: • void acl_aio_read(ACL_ASTREAM *astream); • 示例: • static int __gets_callback(ACL_ASTREAM* client, void* ctx, char* line, int dlen) • { • printf(“gets: %s, len: %d\r\n”, line, dlen); • if (strcasecmp(line, “QUIT”) == 0) { • acl_aio_iocp_close(client); // 当IO完成后关闭流 • return -1; • } • return 0; • } • static void do_something(ACL_ASTREAM* client) • { • acl_aio_add_read_hook(client, __gets_callback, NULL); // 添加流的异步读回调,可以添加多个 • acl_aio_gets_nonl(client); // 异步读一行数据,末尾不带\r\n • }

  26. 客户端接口—写操作 --非阻塞网络编程 • 回调函数类型:typedef int (*ACL_AIO_WRITE_FN)(ACL_ASTREAM *astream, void *context); • 主要函数: • 1)添加异步写成功回调函数 • void acl_aio_add_write_hook(ACL_ASTREAM *astream, ACL_AIO_WRITE_FN callback, void *ctx); • 2)删除异步写回调函数 • void acl_aio_del_write_hook(ACL_ASTREAM *astream, • ACL_AIO_WRITE_FN callback, void *ctx); • 3)异步写指定长度数据 • void acl_aio_writen(ACL_ASTREAM *astream, const char *data, int dlen); • 4)类似 printf 格式异步写数据 • void acl_aio_fprintf(ACL_ASTREAM *astream, const char *fmt, ...); • void acl_aio_vfprintf(ACL_ASTREAM *astream, const char *fmt, va_list ap); • 5)异步写一组数据 • void acl_aio_writev(ACL_ASTREAM *astream, const struct iovec *vector, int count); • 示例: • static int __write_callback(ACL_ASTREAM* client, void* ctx) • { • printf(“write to peer ok\r\n”); • return (0); • } • static void do_something(ACL_ASTREAM* client) • { • acl_aio_add_write_hook(client, __write_callback, NULL); // 添加流异步写的回调函数,可添加多个 • acl_aio_writen(client, “hello\r\n”, sizeof(“hello\r\n”) – 1); // 异步写 • acl_aio_fprintf(client, “How are you\r\n”); // 异步写 • }

  27. 客户端接口—远程连接 --- 非阻塞网络编程 • 回调函数类型定义:typedef int (*ACL_AIO_CONNECT_FN)(ACL_ASTREAM *cstream, void *context); • 主要函数: • 1)添加连接成功回调函数 • void acl_aio_add_connect_hook(ACL_ASTREAM *astream, ACL_AIO_CONNECT_FN callback, void *ctx); • 2)删除连接成功回调函数 • void acl_aio_del_connect_hook(ACL_ASTREAM *astream, ACL_AIO_CONNECT_FN callback, void *ctx); • 3)异步连接 • ACL_ASTREAM *acl_aio_connect(ACL_AIO *aio, const char *saddr, int timeout); • 示例: • static int __connect_callback(ACL_ASTREAM* client, void* ctx) • { • do_somethine(client); • return 0; • } • static void test_connect(ACL_AIO* aio, const char* addr) • { • ACL_ASTREAM* client = acl_aio_connect(aio, addr, 10); // 异步连接服务器 • if (client == NULL) { • printf(“connect %s error(%s)\r\n”, addr, acl_last_serror()); • return; • } • acl_aio_add_connect_hook(client, __connect_callback, NULL); // 添加流异步连接的回调函数 • }

  28. 读写超时及关闭回调接口---非阻塞网络编程 • 回调函数类型: • 1)超时回调接口: • typedef int (*ACL_AIO_TIMEO_FN)(ACL_ASTREAM *astream, void *context); • 2)关闭回调接口: • typedef int (*ACL_AIO_CLOSE_FN)(ACL_ASTREAM *astream, void *context); • 主要函数: • 1)添加读写超时回调函数 • void acl_aio_add_timeo_hook(ACL_ASTREAM *astream, ACL_AIO_TIMEO_FN callback, void *ctx); • 2)删除超时回调函数 • void acl_aio_del_timeo_hook(ACL_ASTREAM *astream, ACL_AIO_TIMEO_FN callback, void *ctx); • 示例: • static int __timeout_callback(ACL_ASTREAM* client, void* ctx) • { • return -1; // 返回负值通知框架关闭该异步注连接,若返回 >= 0 则继续等待 • } • static int __close_callback(ACL_ASTREAM* client, void* ctx) • { • return 0; • } • static void set_callback(ACL_ASTREAM* client, int timeout) • { • acl_aio_ctl(client, ACL_AIO_CTL_TIMEOUT, timeout, • ACL_AIO_CTL_TIMEO_FN, __timeout_callback, ACL_AIO_CTL_END); • }

  29. 服务端例子 -- 非阻塞网络编程 • #include “lib_acl.h” • static int __stop = 0; • static int __accept_callback(ACL_ASTREAM* client, void* ctx) • { • acl_aio_add_read_hook(client, __read_callback, NULL); // 设置流的异步读回调函数 • acl_aio_add_write_hook(client, __write_callback, NULL); // 设置流的异步写回调函数 • acl_aio_gets_nonl(client); // 异步读一行数据,并且自动去掉末尾的 \r\n • return 0; • } • int main(int argc, const char* argv[]) • { • ACL_AIO* aio = acl_aio_create(ACL_EVENT_KERNEL); // 创建异步引擎 • ACL_ASTREAM* sstream; • ACL_VSTREAM* server = acl_vstream_listen(“127.0.0.1:8080”, 128); // 监听 • acl_assert(server); • sstream = acl_aio_open(aio, server); // 打开异步监听流 • acl_aio_ctl(sstream, ACL_AIO_CTL_ACCEPT_FN, __accept_callback, ACL_AIO_CTL_END); // 设置回调函数 • while (1) { • If (__stop) • break; • acl_aio_loop(aio); // 异步事件循环 • } • acl_aio_free(aio); // 释放异步事件引擎 • return 0; • }

  30. 服务端例子 ---非阻塞网络编程 • static int __read_callback(ACL_ASTREAM* client, void* ctx, char* data, int dlen) • { • printf(“gets: %s\n”, data); • If (strcasecmp(data, “quit”) == 0) { • acl_aio_iocp_close(client); // 关闭异步流 • Return -1; • } else if (strcasecmp(data, “stop”) == 0) { • __stop = 1; • return -1; • } • acl_aio_fprintf(client, “%s\r\n”, data); // 异步写一行数据 • return 0; • } • static int __write_callback(ACL_ASTREAM* client, void* ctx) • { • return 0; • } • static int __timeout_callback(ACL_ASTREAM* client, void* ctx) • { • printf(“client read timeout\r\n”); • return 0; • } • static int __close_callback(ACL_ASTREAM* client, void* ctx) • { • printf(“client close now\r\n”); • return 0; • }

  31. 客户端例子 ---非阻塞网络编程 • #include “lib_acl.h” • static int __stop = 0; • static int __connect_callback(ACL_ASTREAM* client, void* ctx) • { • static const char* mydata = “connection!”; • acl_aio_add_read_hook(client, __read_callback, NULL); // 设置异步读回调函数 • acl_aio_add_write_hook(client, __write_callback, NULL); // 设置异步写回调函数 • acl_aio_gets_nonl(client); // 异步读一行数据且不带 \r\n • acl_aio_fprintf(client, “hello world, %s\r\n”, mydata); // 异步写一行数据 • return 0; • } • int main(int argc, const char* argv[]) • { • const char* addr = “127.0.0.1:8080”; • ACL_AIO* aio = acl_aio_create(ACL_EVENT_SELECT); // 创建一个异步引擎 • ACL_ASTREAM* client; • int timeout = 10; • client = acl_aio_connect(aio, addr, timeout); // 异步连接服务器 • If (client == NULL) { • printf(“connect %s error(%s)\r\n”, addr, acl_last_serror()); • return 1; • } • while (1) { • If (__stop) • break; acl_aio_loop(aio); // 异步引擎循环 • } • acl_aio_free(aio); // 释放异步引擎 • return 0; • }

  32. 数据库编程 • 数据库连接池 • 数据库SQL操作

  33. 数据库连接池 • 数据结构类型:ACL_DB_POOL, ACL_DB_HANDLE, ACL_DB_INFO • 主要函数: • 1)创建连接池对象:ACL_DB_POOL *acl_dbpool_create(const char *db_type, const ACL_DB_INFO *db_info); • 2)销毁连接池对象:void acl_dbpool_destroy(ACL_DB_POOL *db_pool); • 3)从连接池获取连接对象:ACL_DB_HANDLE *acl_dbpool_peek(ACL_DB_POOL *db_pool); • 4)将连接对象转为实际连接对象:void *acl_dbpool_export(ACL_DB_HANDLE *db_handle); • 5)将连接对象归还连接池:void acl_dbpool_release(ACL_DB_HANDLE *db_handle); • 6)手动关闭连接对象:void acl_dbpool_close(ACL_DB_HANDLE *db_handle); • 示例: • 一、创建连接池对象,实际上并不连接数据库 • ACL_DB_POOL * dbconn_init(const char* dbaddr, const char* dbname, const char* dbuser, const char* dbpass, • int dbpool_max, int dbping, int dbtimeout) { ACL_DB_POOL *db_pool; ACL_DB_INFO db_info; //初始化连接池的参数 memset(&db_info, 0, sizeof(ACL_DB_INFO)); ACL_SAFE_STRNCPY(db_info.db_addr, dbaddr, sizeof(db_info.db_addr)); // 数据库地址,如:/tmp/mysql.sock 或 127.0.0.1:3306 ACL_SAFE_STRNCPY(db_info.db_name, dbname, sizeof(db_info.db_name)); //数据库名称 ACL_SAFE_STRNCPY(db_info.db_user, dbuser, sizeof(db_info.db_user)); // 数据库帐号 ACL_SAFE_STRNCPY(db_info.db_pass, dbpass, sizeof(db_info.db_pass)); // 数据库帐号密码 db_info.db_max = dbpool_max; // 最大连接个数 db_info.ping_inter = dbping; // 探测每个连接的时间间隔 db_info.timeout_inter = dbtimeout; // 每个连接的最长空闲时间 db_info.auto_commit = 1; // 自动提交修改过程 db_pool = acl_dbpool_create(“mysql”, &db_info); // 创建连接池 if (db_pool == NULL) acl_msg_fatal("%s(%d), %s: init db pool error", __FILE__, __LINE__, __FUNCTION__); return (db_pool); } 参考:lib_acl/include/db/acl_dbpool.h

  34. 数据库SQL操作 • 数据结构类型:ACL_SQL_RES • 主要函数: • 1)SQL查询:ACL_SQL_RES *acl_dbsql_select(ACL_DB_HANDLE *handle, • const char *sql, int *error); • 2)释放查询结果:void acl_dbsql_free_result(ACL_DB_HANDLE *handle, ACL_SQL_RES *res); • 3)SQL更新或添加:int acl_dbsql_update(ACL_DB_HANDLE *handle, const char *sql, int *error); • 示例: • 一、SQL查询过程 • static ACL_DB_POOL* __dbpool; // 需要提前创建连接池对象 • int sql_select_test(void) • { • const char* sql = “select name, age, pass from user_tbl where age >= 20”; • ACL_SQL_RES* result; // 查询结果集 • ACL_ITER iter; // 遍历指针 • int error = 0, n = 0; • ACL_DB_HANDLE* conn = acl_dbpool_peek(__dbpool); // 从连接池中获得数据库连接 • If (conn == NULL) { • acl_msg_error(“%s(%d), %s: get connection error”, __FILE__, __LINE__, __FUNCTION__); return -1; • } • result = acl_dbsql_select(conn, sql, &error); // 进行数据库SQL查询 • if (retsult == NULL) { • If (error != ACL_DB_OK && error != ACL_DB_ERR_EMPTY) { • acl_msg_error(“%s(%d), %s: sql select error: %d”, __FILE__, __LINE__, __FUNCTION__, error); • Acl_dbpool_close(conn); // 关闭连接 } else • acl_dbpool_release(conn); // 归还连接至连接池中 • return -1; • } • acl_dbpool_release(conn); // 归还连接至连接池中 • acl_foreach(iter, result) { // 遍历查询结果集 • const char** rows = (const char**) iter.data; • printf(“name: %s, age: %s, pass: %s\r\n”, rows[0], rows[1], rows[2]); • n++; • } • acl_dbsql_free_result(conn, res); // 释放查询结果集 • return n; • } • 参考:lib_acl/include/db/acl_dbsql.h

  35. 更新数据库操作---数据库编程示例 • 二、数据库 添加/修改/删除 过程 • static ACL_DB_POOL* __dbpool = NULL; // 需要提前创建连接池对象 • int sql_insert_test(void) • { • const char* sql = “insert into user(name, age, pass) values(‘myname’, 29, ‘hello’)”; • // const char* sql = “update user set age = 30 where name = ‘myname’”; • // const char* sql = “delete from user where name = ‘myname’”; • MYSQL* mysql; • int ret, error = 0, n; • ACL_DB_HANDLE* conn = acl_dbpool_peek(__dbpool); // 从连接池中获得数据库连接 • If (conn == NULL) { • acl_msg_error(“%s(%d), %s: get connection error”, __FILE__, __LINE__, __FUNCTION__); return -1; • } • ret = acl_dbsql_update(conn, sql, &error); // 更新数据库 • mysql = (MYSQL*) acl_dbpool_export(conn); // 从连接对象中导出 mysql 连接对象 • n = mysql_affected_rows(mysql); // 记录更新操作影响的行数 • acl_dbpool_release(conn); // 释放数据库连接,归还给连接池 • if (ret < 0) • acl_msg_error(“%s(%d), %s: update db error: %d”, __FILE__, __LINE__, __FUNCTION__, error); else acl_msg_info(“%s(%d), %s: affected: %d”, __FILE__, __LINE__, __FUNCTION__, n); return ret; • } • 参考:lib_acl/include/db/acl_dbsql.h, acl_dbpool.h

  36. XML解析库 • 结构类型及常用API函数 • Xml 解析示例 • Xml 树遍历 • Xml 结点遍历 • Xml 结点查询 • Xml 结点属性查询

  37. XML解析库 • 数据结构类型:ACL_XML, ACL_XML_NODE, ACL_XML_ATTR • 主要函数: • 1)创建 xml 解析器:ACL_XML *acl_xml_alloc(void); • 2)释放 xml 解析器:int acl_xml_free(ACL_XML *xml); • 3)将一个 xml 结点对象转换为xml解析器:void acl_xml_foreach_init(ACL_XML *xml, ACL_XML_NODE *node); • 4)重置 xml 解析器(在需要重复使用 xml 解析器时):void acl_xml_reset(ACL_XML *xml); • 5)设置 xml 解析器缓存(重复使用 xml 解析器提高效率):void acl_xml_cache(ACL_XML *xml, int max); • 6)流式方式解析 xml 数据:void acl_xml_update(ACL_XML *xml, const char *data); • 7)获得 xml 结点集合 • 7.1)ACL_ARRAY *acl_xml_getElementsByTagName(ACL_XML *xml, const char *tag); • 7.2)ACL_ARRAY *acl_xml_getElementsByTags(ACL_XML *xml, const char *tags); • 7.3)ACL_ARRAY *acl_xml_getElementsByAttr(ACL_XML *xml, const char *name, const char *value); • 7.4)ACL_ARRAY *acl_xml_getElementsByName(ACL_XML *xml, const char *value); • 8)根据ID获得 xml 结点:ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id); • 9)获得 xml 结点中的属性对象 • 9.1)ACL_XML_ATTR *acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name); • 9.2)ACL_XML_ATTR *acl_xml_getAttrById(ACL_XML *xml, const char *id); • 10)获得 xml 结点中属性值 • 10.1)const char *acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name); • 10.2)ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id); • 11)遍历: • 11.1)遍历 xml 树:acl_foreach(iter, ACL_XML*) {} • 11.2)遍历 xml 结点:acl_foreach(iter, ACL_XML_NODE*) {} • 参考:lib_acl/include/xml/acl_xml.h

  38. Xml 解析示例 • #include “lib_acl.h” • static const char *__data = \ • "<root id='tt' name=‘xxxx’ value=‘xxxxx’ id=‘id_0001’>hello <root2> hi </root2></root><br/>\r\n"; • static void xml_parse_once(ACL_XML* xml) • { • acl_xml_update(xml, __data); // 更新 xml 解析器数据 • if (acl_xml_is_closure(xml)) // 检查 xml 解析器是否获得了完整的 xml 数据 • printf(“all xml data parse over\r\n”); else printf(“some xml data not update\r\n”); • } • static void xml_parse_part(ACL_XML* xml) • { • const char* ptr = __data; • char buf[2]; • while (*ptr) { • buf[0] = *ptr; • buf[1] = 0; • acl_xml_update(xml, buf); // 更新 xml 解析器数据,每次输入一个 xml 字节数据 } • } • int main(int argc acl_unused, char* argv[] acl_unused) • { • ACL_XML* xml = acl_xml_alloc(); // 创建 xml 解析器对象 • xml_parse_once(xml); // 一次性解析整个 xml 数据 • acl_xml_reset(xml); // 重置 xml 解析器状态,以备下一个解析过程 • xml_parse_part(xml); // 流式解析 xml 数据 • acl_xml_free(xml); // 释放 xml 解析器对象 • return 0; • } • 参考:lib_acl/include/xml/acl_xml.h, samples/xml

  39. 遍历 xml树 • void xml_iterator(ACL_XML* xml) • { • ACL_ITER iter1, iter2; • #define STR acl_vstring_str • #define LEN ACL_VSTRING_LEN /* 从根结点开始遍历 xml 对象的所有结点 */ acl_foreach(iter1, xml) { ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; for (i = 1; i < node->depth; i++) { printf("\t"); } printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); /* 遍历 xml 结点的属性 */ acl_foreach(iter2, node->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; for (i = 1; i < node->depth; i++) { printf("\t"); } printf("\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); } } • }

  40. 遍历 xml 结点的第一级子结点 • void xml_node_iterator(ACL_XML* xml) • { • ACL_ITER iter1, iter2, iter3; • /* 遍历根结点的一级子结点 */ • acl_foreach(iter1, xml->root) { • ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; • printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); • /* 遍历一级子结点的一级子结点 */ • acl_foreach(iter2, node) { • ACL_XML_NODE *node2 = (ACL_XML_NODE*) iter2.data; • printf("\ttag> %s, text: %s\n", STR(node2->ltag), STR(node2->text)); • /* 遍历一级子结点的属性 */ • acl_foreach(iter3, node2->attr_list) { • ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter3.data; • printf("\t\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); • } • } • } • }

  41. 遍历 xml 结点以及所有的子结点 • void xml_node_iterator_all(ACL_XML_NODE* node) • { • ACL_XML xml; • ACL_ITER iter1, iter2; • #define STR acl_vstring_str • #define LEN ACL_VSTRING_LEN • acl_xml_foreach_init(&xml, node); // 将 xml 结点转为 xml 树对象 /* 从根结点开始遍历 xml 对象的所有结点 */ acl_foreach(iter1, xml) { ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; for (i = 1; i < node->depth; i++) { printf("\t"); } printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); /* 遍历 xml 结点的属性 */ acl_foreach(iter2, node->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; for (i = 1; i < node->depth; i++) { printf("\t"); } printf("\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); } } • }

  42. xml 结点查询 • 一、根据标签名获得 xml 结点集合 • void xml_node_lookup1(ACL_XML* xml) • { • ACL_ITER iter; • ACL_ARRAY* a; • a = acl_xml_getElementsByTagName(xml, "user"); • if (a) { • /* 遍历结果集 */ • acl_foreach(iter1, a) { • ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; • printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); • } • /* 释放数组对象 */ • acl_xml_free_array(a); • } • } • 二、查询属性名为 name, 属性值为 user2_1 的所有 xml 结点的集合 • void xml_node_lookup2(ACL_XML* xml) • { • ACL_ITER iter; • ACL_ARRAY* a; • a = acl_xml_getElementsByName(xml, "user2_1"); • if (a) { • /* 遍历结果集 */ • acl_foreach(iter1, a) { • ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; • printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); • } • /* 释放数组对象 */ • acl_xml_free_array(a); • } • }

  43. XML 结点查询 • 三、从 xml 对象中获得所有的与给定多级标签名相同的 xml 结点的集合 • void xml_node_lookup3(ACL_XML* xml) • { • ACL_ARRAY* a; • const char* tags = “root/root2”; • a = acl_xml_getElementsByTags(xml, tags); • if (a) { • ACL_ITER iter; • acl_foreach(iter, a) { • ACL_XML_NODE* node = (ACL_XML_NODE*) iter.data; • … • } • acl_xml_free_array(a); • } • } • 四、从 xml 对象中获得指定 id 值的 xml 结点元素 • void xml_node_lookup4(ACL_XML* xml) • { • #define STR acl_vstring_str • ACL_XML_NODE* node = acl_xml_getElementById(xml, "id2_3"); • if (node) { • printf("-------------- walk %s node -------------------\n", STR(pnode->ltag)); • /* 遍历该 xml 结点的属性 */ • acl_foreach(iter1, pnode->attr_list) { • ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; • printf("\tattr_name: %s, attr_value: %s\n", • STR(attr->name), STR(attr->value)); • } • } • }

  44. Xml 结点属性查询 • static void xml_node_attr(ACL_XML_NODE* node) • { • Const char* ptr; • ACL_XML_ATTR* attr; • ptr = acl_xml_getElementAttrVal(node, “name”); // 根据属性名获得属性值 • if (ptr) • printf(“name: %s\r\n”, ptr); attr = acl_xml_getAttrValueById(node->xml, “id_001”); // 根据属性唯一ID号获得属性对象 if (attr) printf(“id: %s\n”, acl_vstring_str(attr->value)); attr = acl_xml_getElementAttr(node, “name”); // 根据属性名获得属性对象 if (attr) printf(“id: %s\n”, acl_vstring_str(attr->value)); • }

  45. JSON解析 • 结构类型及常用API函数 • json 解析示例 • json 树遍历 • json 结点遍历 • json 结点查询

  46. 结构类型及常用API函数---JSON解析 • 数据结构类型:ACL_JSON, ACL_JSON_NODE • 主要函数: • 1)创建 json 解析器对象:ACL_JSON *acl_json_alloc(void); • 2)释放 json 解析器对象:int acl_json_free(ACL_JSON *json); • 3)将 json 结点转换为 json 树对象:void acl_json_foreach_init(ACL_JSON *json, ACL_JSON_NODE *node); • 4)启用 json 解析器的缓存机制:void acl_json_cache(ACL_JSON *json, int max_cache); • 5)重置 json 解析器状态:void acl_json_reset(ACL_JSON *json); • 6)流式方式给 json 解析器输入数据:void acl_json_update(ACL_JSON *json, const char *data); • 7)获得 json 结点集 • 7.1)根据标签名获得:ACL_ARRAY *acl_json_getElementsByTagName(ACL_JSON *json, const char *tag); • 7.2)根据多级标签名获得: • ACL_ARRAY *acl_json_getElementsByTags(ACL_JSON *json, const char *tags); • 8)释放 json 结点集:void acl_json_free_array(ACL_ARRAY *a); • 参考:lib_acl/include/stdlib/acl_json.h

  47. json 解析示例 • static const char* default_data = \ • "{'menu': {\r\n" • " 'id': 'file',\r\n" • " 'value': 'File',\r\n" • " 'popup': {\r\n" • " 'menuitem': [\r\n" • " {'value': 'New', 'onclick': 'CreateNewDoc()'},\r\n" • " {'value': 'Open', 'onclick': 'OpenDoc()'},\r\n" • " {'value': 'Close', 'onclick': 'CloseDoc()'}\r\n" • " ],\r\n" • " 'menuname': 'hello world'\r\n" • " }\r\n" • "}}\r\n"; • static void test_json_data(const char* data) • { • ACL_JSON* json = acl_json_alloc(); // 创建 json 解析器 • const char* ptr = data; • char buf[2]; • while (*ptr) • { • buf[0] = *ptr++; • buf[1] = 0; • acl_json_update(json, buf); // 流式方式输入 json 数据 • if (json->finish) • break; • } • acl_json_free(json); // 释放 json 解析器对象 • }

  48. json 树遍历 • static void test_json_foreach(ACL_JSON* json) • { • ACL_ITER iter; • #define STR acl_vstring_str • acl_foreach(iter, json) // 遍历 json 所有结点 • { • const ACL_JSON_NODE* node = (const ACL_JSON_NODE*) iter.data; • for (int i = 1; i < node->depth; i++) // 根据结点层级输出 tab • printf("\t"); • printf("tag> %s, %s, text: %s, child: %s, type: %s\n", • STR(node->ltag), STR(node->parent->ltag), • STR(node->text), node->tag_node ? "yes" : "no", • acl_json_node_type(node)); • } • }

  49. json 结点遍历 • static void test_json_find1(ACL_JSON* json) • { • const char* tags = "menu/popup/menuitem"; • ACL_ARRAY* a = acl_json_getElementsByTags(json, tags); // 获得结点对象集 • ACL_ITER iter1, iter2, iter3; • if (a == NULL) • return; • printf(">>find: %s\r\n", tags); • acl_foreach(iter1, a) { • ACL_JSON_NODE* node1 = (ACL_JSON_NODE*) iter1.data; • printf("%s: %s\r\n", tags, STR(node1->text)); • acl_foreach(iter2, node1) { • ACL_JSON_NODE* node2 = (ACL_JSON_NODE*) iter2.data; • acl_foreach(iter3, node2) { • ACL_JSON_NODE* node3 = (ACL_JSON_NODE*) iter3.data; • printf("\t%s: %s\r\n", STR(node3->ltag), STR(node3->text)); • } • printf("---------------------------------------------------\r\n"); • } • } • printf(">>find %s end\r\n", tags); • acl_json_free_array(a); • }

  50. json 结点查询 • static void test_json_find2(ACL_JSON* json) • { • const char* tag = "onclick"; • ACL_ITER iter; • ACL_ARRAY* a = acl_json_getElementsByTagName(json, tag); • if (a == NULL) • return; • acl_foreach(iter, a) { • ACL_JSON_NODE* node = (ACL_JSON_NODE*) iter.data; • printf("find %s result: %s\r\n", tag, STR(node->text)); • } • acl_json_free_array(a); • } • static void test_json_find1(ACL_JSON* json) • { • const char* tags = "menu/popup/menuname"; • ACL_ARRAY* a = acl_json_getElementsByTags(json, tags); • ACL_ITER iter; • if (a == NULL) • return; • acl_foreach(iter, a) { • ACL_JSON_NODE* node = (ACL_JSON_NODE*) iter.data; printf("find %s result: %s\r\n", tag, STR(node->text)); • } • acl_json_free_array(a); • }

More Related