libcc 是一个轻量级、跨平台的 C 语言库,专注于为开发者提供简洁高效的基础设施接口和丰富的协议支持。其核心设计理念是:
核心功能
libcc 提供以下核心功能模块:
适用场景
libcc 特别适合以下场景:
Step 1. 按照Build Tools设置开发环境,确保系统已安装必要的编译工具链(如 GCC、Clang 或 MSVC)。
Step 2. 包含libcc头文件到你的源代码项目中,确保路径配置正确。
Step 3. 将以下代码段添加到main.c文件中,这是一个简单的多线程示例,展示 libcc 的基本用法:
#include <libcc.h>
static _cc_thread_local_t int thread_local_value = 0;
static int global_value = 0;
static int32_t fn(void *args) {
global_value++;
thread_local_value++;
printf("Global value:%d!\nThread local value:%d!\n", global_value,thread_local_value);
return 0;
}
int main(int argc, char *const argv[]) {
_cc_thread_t *thread[10];
//创建10个线程
for (i = 0; i < _cc_countof(thread); i++) {
thread[i] = _cc_thread(fn, "work thread", nullptr);
}
for (i = 0; i < _cc_countof(thread); i++) {
int32_t state = 0;
_cc_wait_thread(thread[i], &state);//等待线程退出
}
return 0;
}
Step 4. 编译并运行。
libcc 使用事件标志来标识不同类型的事件和描述符属性。这些标志可以组合使用,以满足不同的应用场景需求。
#define _CC_EVENT_UNKNOWN_ 0x0000 /**< 未设置的事件标识 */
#define _CC_EVENT_ACCEPT_ 0x0001 /**< 可接受新连接的事件标识 */
#define _CC_EVENT_WRITABLE_ 0x0002 /**< 可写入数据的事件标识 */
#define _CC_EVENT_READABLE_ 0x0004 /**< 可读取数据的事件标识 */
#define _CC_EVENT_CONNECT_ 0x0008 /**< 连接成功或失败的事件标识 */
#define _CC_EVENT_CLOSED_ 0x0080 /**< 连接或文件描述符关闭的事件标识 */
#define _CC_EVENT_PENDING_ 0x0100 /**< 事件待处理标识 */
#define _CC_EVENT_SOCKET_UDP_ 0x0200 /**< 描述符为 UDP 协议的事件标识 */
#define _CC_EVENT_SOCKET_IPV6_ 0x0400 /**< Socket 连接为 IPv6 的事件标识 */
#define _CC_EVENT_NONBLOCKING_ 0x1000 /**< 非阻塞模式的事件标识 */
#define _CC_EVENT_CLOEXEC_ 0x2000 /**< 子进程不继承描述符的事件标识 */
/** Used in _cc_event_t to determine what the fd is */
#define _CC_EVENT_SOCKET_ 0x010000 /**< 描述符为 Socket 的事件标识 */
#define _CC_EVENT_FILE_ 0x020000 /**< 描述符为文件的事件标识 */
#define _CC_EVENT_TIMEOUT_ 0x040000 /**< 超时事件标识 */
常见标志组合
_CC_EVENT_READABLE | _CC_EVENT_WRITABLE - 同时监听读写事件_CC_EVENT_ACCEPT | _CC_EVENT_NONBLOCKING - 非阻塞模式下的接受连接事件_CC_EVENT_SOCKET | _CC_EVENT_SOCKET_UDP - UDP 套接字事件使用建议
_CC_EVENT_ACCEPT 事件_CC_EVENT_READABLE 和 _CC_EVENT_WRITABLE 事件_CC_EVENT_NONBLOCKING 可以提高 I/O 性能_CC_EVENT_CLOEXEC 可以防止子进程继承不需要的文件描述符libcc 支持多种构建方式,以适应不同的开发环境和目标平台。以下是主要的构建选项:
1. 通过 Makefile 编译 (Linux, FreeBSD, macOS)
# 下载源码
git clone https://github.com/libcc/libcc.git
cd libcc
# 编译静态库(适用于需要静态链接的场景)
make .a platform=linux debug=1
# 编译动态库(适用于需要动态加载的场景)
make .so platform=linux debug=1
# 或者使用构建脚本
cd ./build
./build.sh debug
适用场景: Linux/Unix 环境下的开发,需要自定义编译选项的场景。
2. Windows 下 MSYS2 环境执行
./build.cmd debug
适用场景: Windows 平台下的开发,需要兼容 Unix 工具链的场景。
3. 通过 Visual Studio 编译 (Windows)
proj.Win/libcc.vcxproj
适用场景: Windows 平台下的原生开发,需要 Visual Studio 集成的场景。
4. 通过 Android JNI 编译
# 配置 NDK 环境
cd proj.Android/JNI
$NDK/ndk-build NDK_DEBUG=1
# 或者使用构建脚本
./build_NDK.sh
适用场景: Android 平台下的原生开发,需要通过 JNI 集成的场景。
5. 通过 Xcode 编译 (macOS, iOS)
proj.OSX/cc.xcodeproj
proj.IOS/cc.xcodeproj
适用场景: macOS 和 iOS 平台下的开发,需要 Xcode 集成的场景。
USE_LIB_URL_REQUEST=1 - 启用 URL 请求模块USE_LIB_MYSQL=1 - 启用 MySQL 数据库支持USE_LIB_SQLITE3=1 - 启用 SQLite 数据库支持USE_LIB_SMTP=1 - 启用 SMTP 邮件发送支持USE_LIB_OPENSSL=1 - 启用 OpenSSL 加密支持本页面既是 API 参考,也是教程入口。下面列出一组建议的入门教程(均可作为后续页面或示例拓展):
每个教程都可配套一个小示例(放在 tests/ 目录或新建 examples/)。
libcc 事件系统的核心数据结构,用于表示和管理各种 I/O 事件、定时器事件等。
typedef struct _cc_event _cc_event_t;
struct _cc_event {
/* 当前事件标识,如:读、写、连接、监听、定时器 等事件 _CC_EVENT_* flags */
uint32_t flags;
/* 标识哪些事件已经提交给系统了。如:读事件提交给epoll,kqueue,iocp等
* 主要通过flags判断是否发生变化,防止事件重复多次提交
*/
uint32_t filter;
/* 事件唯一ID,通过0xFFF(async index)FFFFF(self index) 可以获取到对应的指针*/
uint32_t ident;
/* Socket、文件描述符 */
_cc_socket_t fd;
/* 入侵式链表双向指针,_cc_async_event_t结构体中管理,时间轮链表,no_timer链表 */
_cc_list_iterator_t lnk;
/* 事件回调函数 可读、可写、超时等事件通知. */
_cc_event_callback_t callback;
/* 用户绑定的参数. */
uintptr_t data;
/* 事件时间轮的超时时间 */
uint32_t timeout;
/* 当前事件时间轮时间曹位 */
uint32_t expire;
#ifdef _CC_EVENT_USE_IOCP_
/*iocp accept 的Socket描述符*/
_cc_socket_t accept_fd;
#endif
};
字段说明
flags - 当前事件标识,使用 _CC_EVENT_* 宏定义组合filter - 已提交给系统的事件标识,用于防止重复提交ident - 事件唯一 ID,用于快速查找fd - 关联的文件描述符或套接字lnk - 链表指针,用于事件管理器内部维护,时间轮callback - 事件回调函数,原型为 typedef void (*_cc_event_callback_t)(_cc_event_t* e, uint32_t which);data - 用户自定义数据指针示例
// 创建事件
_cc_event_t *event = _cc_event_alloc(async, _CC_EVENT_READABLE);
event->fd = socket_fd;
event->callback = on_socket_event;
event->data = user_data;
// 注册事件
...
// 事件回调函数示例
static void on_socket_event(_cc_async_event_t *async, _cc_event_t *e, const uint32_t which) {
if (which & _CC_EVENT_READABLE) {
// 处理可读事件
}
if (which & _CC_EVENT_WRITABLE) {
// 处理可写事件
}
}
注意事项
事件结构体,作用与套接字、定时器等事件。
typedef struct _cc_async_event _cc_async_event_t;
struct _cc_async_event {
/*是否运行中*/
byte_t running;
/*唯一ID*/
uint16_t ident;
/*事件回调计数*/
int32_t processed;
/*时间轮相关*/
uint32_t timer;
uint32_t diff;
uint64_t tick;
/*时间轮的时间曹 双向链表*/
_cc_list_iterator_t nears[_CC_TIMEOUT_NEAR_];
_cc_list_iterator_t level[_CC_TIMEOUT_MAX_LEVEL_][_CC_TIMEOUT_LEVEL_];
/*待处理事件*/
_cc_list_iterator_t pending;
/*没有定时的事件 双向链表*/
_cc_list_iterator_t no_timer;
/*多线程安全锁*/
#ifdef _CC_EVENT_USE_MUTEX_
_cc_mutex_t *lock;
#else
/*使用自旋锁,只对时间轮双向链表push和pop操作锁*/
_cc_atomic_lock_t lock;
#endif
/*发生变化的事件,需要重新调整的缓存数组*/
_cc_array_t changes;
/*私有的数据内部使用在各平台的参数,如kqueue,epoll,iocp */
_cc_async_event_priv_t *priv;
/* 携带用户的参数*/
pvoid_t args;
/*事件接口 select,epoll,kqueue,iocp 统一接口*/
/*对事件重置,放入changs数组等待统一处理*/
bool_t (*reset)(_cc_async_event_t *async, _cc_event_t *e);
/*新事件,放入changs数组等待统一处理*/
bool_t (*attach)(_cc_async_event_t *async, _cc_event_t *e);
/**/
bool_t (*connect)(_cc_async_event_t *async, _cc_event_t *e, const _cc_sockaddr_t *sa, const _cc_socklen_t sa_len);
/**/
_cc_socket_t (*accept)(_cc_async_event_t *async, _cc_event_t *e, _cc_sockaddr_t *sa, _cc_socklen_t *sa_len);
/**/
bool_t (*disconnect)(_cc_async_event_t *async, _cc_event_t *e);
/**/
bool_t (*wait)(_cc_async_event_t *async, uint32_t timeout);
/**/
bool_t (*free)(_cc_async_event_t *async);
};
async 事件管理结构,包含活动事件列表以及一些管理信息和跨平台接口。epoll、kqueue、iocp、时间轮等
_CC_API_PUBLIC(_cc_event_t*) _cc_event_alloc(_cc_async_event_t *async, const uint32_t flags);
分配并初始化一个新的事件结构体,用于管理套接字、文件描述符或定时器事件。此函数是 libcc 事件驱动模型的核心接口之一,适用于高并发网络编程场景。
参数:
_CC_EVENT_READABLE - 可读事件_CC_EVENT_WRITABLE - 可写事件_CC_EVENT_TIMEOUT - 超时事件_CC_EVENT_PENDING - 待处理事件返回值:
示例:
_cc_async_event_t *async = _cc_async_event_create();
_cc_event_t *event = _cc_event_alloc(async, _CC_EVENT_READABLE | _CC_EVENT_WRITABLE);
if (event) {
// 事件分配成功,可以进一步配置和使用
}
注意事项:
_CC_API_PUBLIC(void) _cc_free_event(_cc_async_event_t *async, _cc_event_t *e);
释放事件资源并关闭相关连接。此函数是 libcc 事件生命周期管理的关键接口,用于安全地释放事件占用的所有资源,包括:
参数:
返回值:
无返回值(void)
示例:
_cc_async_event_t async;
_cc_register_select(&async);
_cc_event_t *event = _cc_event_alloc(&async, _CC_EVENT_READABLE);
// ... 使用事件 ...
if (!async.attach(&async)) {
//附加失败,安全释放事件
_cc_free_event(&async, event);
}
...
//无需手动释放
注意事项:
e 将不再可用_CC_API_PUBLIC(_cc_async_event_t *) _cc_get_async_event(void);
获取一个已启用的事件管理器
_CC_API_PUBLIC(_cc_event_t *) _cc_get_event_by_id(uint32_t ident);
通过event中的ident获取_cc_event_t结构体指针
_CC_API_PUBLIC(_cc_async_event_t *) _cc_get_async_event_by_id(uint32_t ident);
通过event中的ident获取_cc_async_event_t结构体指针
_CC_API_PUBLIC(bool_t) _cc_register_select(_cc_async_event_t*);
初始化一个_cc_async_event_t结构体为select
_CC_API_PUBLIC(bool_t) _cc_register_iocp(_cc_async_event_t*);
初始化一个_cc_async_event_t结构体为 Windows IOCP
_CC_API_PUBLIC(bool_t) _cc_register_epoll(_cc_async_event_t*);
初始化一个_cc_async_event_t结构体为 Linux epoll
_CC_API_PUBLIC(bool_t) _cc_register_kqueue(_cc_async_event_t*);
初始化一个_cc_async_event_t结构体为 Unix (mac、BSD) 的kqueue
使用的例子:
_cc_async_event_t async;
_cc_event_t *event;
_cc_register_select(&async, nullptr);
//创建一个定时器
event = _cc_event_alloc(&async, _CC_EVENT_TIMEOUT_);
event->callback = fn_handler;
event->timeout = 1000;
// Event loop
while(async.running) {
async.wait(&async, 1000/* 1 sec */);
}
//关闭所有连接,并释放所有资源。
async.free(&async);
_CC_API_PUBLIC(bool_t) _cc_tcp_listen(_cc_async_event_t *async, _cc_event_t *e, _cc_sockaddr_t *sockaddr, _cc_socklen_t socklen);
创建一个 TCP 监听事件,并将此监听事件附加到异步事件管理器的变更队列中。该函数通常用于服务器端,监听指定地址和端口的 TCP 连接请求。
参数说明
struct sockaddr 结构体的指针,指定监听的地址和端口struct sockaddr 结构体的实际大小返回值
true - 监听事件创建成功false - 监听事件创建失败,通常是由于参数无效或系统资源不足示例代码
_cc_async_event_t *async = _cc_get_async_event;
_cc_event_t *e = _cc_event_alloc(async, _CC_EVENT_ACCEPT);
struct sockaddr_in sa;
_cc_inet_ipv4_addr(&sa, "0.0.0.0", 8080);
if (_cc_tcp_listen(async, e, &sa, sizeof(struct sockaddr_in))) {
printf("TCP 监听已启动,端口: 8080\n");
} else {
printf("TCP 监听启动失败\n");
}
注意事项
async 和 e 已正确初始化_CC_API_PUBLIC(bool_t) _cc_tcp_connect(_cc_async_event_t *async, _cc_event_t *e, _cc_sockaddr_t *sockaddr, _cc_socklen_t socklen);
创建一个 TCP 连接事件,并将此连接事件附加到异步事件管理器的变更队列中。该函数通常用于客户端,发起与指定服务器的 TCP 连接。
参数说明
struct sockaddr 结构体的指针,指定目标服务器的地址和端口struct sockaddr 结构体的实际大小返回值
true - 连接事件创建成功false - 连接事件创建失败,通常是由于参数无效或系统资源不足示例代码
_cc_async_event_t *async = _cc_get_async_event();
_cc_event_t *e = _cc_event_alloc(async, _CC_EVENT_CONNECT);
struct sockaddr_in sa;
_cc_inet_ipv4_addr(&sa, "127.0.0.1", 8080);
if (_cc_tcp_connect(async, e, &addr, sizeof(addr))) {
printf("TCP 连接已发起,目标: 127.0.0.1:8080\n");
} else {
printf("TCP 连接发起失败\n");
}
注意事项
async 和 e 已正确初始化_CC_API_PUBLIC(bool_t) _cc_alloc_async_event(int32_t cores, void (*cb)(_cc_async_event_t*,bool_t));
多线程异步事件
参数:
返回值: true/false
_CC_API_PUBLIC(bool_t) _cc_free_async_event(void);
关闭所有异步事件,并释放所有资源
_CC_API_PUBLIC(void) _cc_async_event_abort(void);
中断异步事件所有线程,负责安全退出
_CC_API_PUBLIC(bool_t) _cc_async_event_is_running(void);
判断是否运行中
使用的例子:
static bool_t fn(_cc_async_event_t *async, _cc_event_t *e, const uint32_t which) {
if (which & _CC_EVENT_TIMEOUT_) {
_cc_logger_debug(_T("%d timer timeout. arg:%ld"), e->ident, e->data);
_cc_async_event_abort();
return false;
} else if (which & _CC_EVENT_CLOSED_) {
_cc_logger_debug(_T("%d destroy timeout. arg:%ld"), e->ident, e->data);
}
//返回false 停止计时器,true 继续定时回调
return true;
}
int main(int argc, char *const argv[]) {
_cc_alloc_async_event(0, nullptr);
//10秒后安全退出
_cc_add_event_timeout(&async, 10000, fn, 1);
// 主线程 loop
while(_cc_async_event_is_running()) {
_cc_sleep(10);
}
//关闭所有连接,并释放所有资源。
_cc_free_async_event();
return 0;
}
_CC_API_PUBLIC(int32_t) _cc_send(_cc_socket_t fd, const byte_t* buf, int32_t length);
通过指定的 Socket 描述符发送数据。该函数是线程安全的,适用于高并发场景。
参数说明
返回值
length_cc_last_error() 获取详细错误信息示例代码
byte_t data[] = "Hello, World!";
int32_t sent = _cc_send(sock_fd, data, strlen(data));
if (sent == -1) {
printf("发送失败,错误码: %d\n", _cc_last_error());
} else {
printf("成功发送 %d 字节数据\n", sent);
}
注意事项
_CC_API_PUBLIC(int32_t) _cc_recv(_cc_socket_t fd, byte_t* buf, int32_t length);
通过指定的 Socket 描述符接收数据。该函数支持阻塞和非阻塞模式,适用于各种网络场景。
参数说明
返回值
_cc_last_error() 获取详细错误信息示例代码
byte_t buffer[1024];
int32_t received = _cc_recv(sock_fd, buffer, sizeof(buffer));
if (received == -1) {
printf("接收失败,错误码: %d\n", _cc_last_error());
} else if (received == 0) {
printf("对端已关闭连接\n");
} else {
printf("成功接收 %d 字节数据: %.*s\n", received, received, buffer);
}
注意事项
_CC_API_PUBLIC(_cc_event_t*) _cc_add_event_timeout(_cc_async_event_t *async, uint32_t ms, _cc_event_callback_t callback, uintptr_t data);
向事件管理器添加一个软计时器。该计时器基于时间轮算法实现,适用于需要周期性触发或延迟触发的场景。
参数说明
true 以继续触发或 false 以停止返回值
NULL,通常是由于参数无效或系统资源不足示例代码
static bool_t fn(_cc_async_event_t *async, _cc_event_t *e, const uint32_t which) {
if (which & _CC_EVENT_TIMEOUT_) {
_cc_logger_debug(_T("%d timer timeout. arg:%ld"), e->ident, e->data);
} else if (which & _CC_EVENT_CLOSED_) {
_cc_logger_debug(_T("%d destroy timeout. arg:%ld"), e->ident, e->data);
//退出Event Loog
async->running = false;
}
//返回false 停止计时器,并释放,true 继续定时触发
return true;
}
_cc_event_t *timer = _cc_add_event_timeout(_cc_get_async_event(), 1000, fn, 10);
if (!timer) {
printf("Failed to create timer\n");
}
注意事项
_cc_kill_event_timeout 释放资源_CC_API_PUBLIC(bool_t) _cc_kill_event_timeout(_cc_async_event_t *async, _cc_event_t *e);
从事件管理器中移除指定的计时器并释放相关资源。该操作是线程安全的。
参数说明
_cc_add_event_timeout 获取返回值
truefalse,通常是由于计时器已被移除或参数无效示例代码
_cc_async_event_t *async = _cc_get_async_event();
_cc_event_t *timer = _cc_add_event_timeout(async, 1000, timer_callback, 0);
// ...
if (!_cc_kill_event_timeout(async, timer)) {
printf("Failed to remove timer\n");
}
注意事项
使用的例子:
static bool_t fn(_cc_async_event_t *async, _cc_event_t *e, const uint32_t which) {
if (which & _CC_EVENT_TIMEOUT_) {
_cc_logger_debug(_T("%d timer timeout. arg:%ld"), e->ident, e->data);
} else if (which & _CC_EVENT_CLOSED_) {
_cc_logger_debug(_T("%d destroy timeout. arg:%ld"), e->ident, e->data);
//退出Event Loog
async->running = false;
}
//返回false 停止计时器,并释放,true 继续定时触发
return true;
}
int main(int argc, char *const argv[]) {
_cc_async_event_t async;
_cc_event_t *event;
_cc_register_timeout(&async, nullptr);
//创建一个定时器
_cc_add_event_timeout(&async, 10000, fn, 1);
//
event = _cc_add_event_timeout(&async, 20000, fn, 2);
//删除定时器
_cc_kill_event_timeout(&async, event);
// Event loop
while(async.running) {
async.wait(&async, 100/* 0.1 sec */);
}
//关闭所有连接,并释放所有资源。
async.free(&async);
return 0;
}
IO buffer 是一种高效的数据结构,用于管理网络 I/O 操作中的数据缓冲。它支持动态增长和收缩,并提供了线程安全的读写操作。
结构定义
typedef struct _cc_io_buffer _cc_io_buffer_t;
typedef struct _cc_io_data {
int32_t limit; // 缓冲区总容量
int32_t off; // 当前数据偏移量
byte_t *bytes; // 数据存储指针
} _cc_io_data_t;
struct _cc_io_buffer {
_cc_io_data_t r; // 读缓冲区
_cc_io_data_t w; // 写缓冲区
_cc_atomic_lock_t lock_of_writable; // 写缓冲区锁
_cc_SSL_t *ssl; // SSL/TLS 上下文
};
成员说明
典型使用场景
注意事项
_CC_API_PUBLIC(_cc_io_buffer_t *) _cc_alloc_io_buffer(int32_t limit);
动态分配一个 IO Buffer 结构体,并初始化其读写缓冲区。
参数说明
返回值
NULL,通常是由于内存不足或参数无效示例代码
_cc_io_buffer_t *buffer = _cc_alloc_io_buffer(4096);
if (!buffer) {
printf("Failed to allocate IO buffer\n");
return;
}
// 使用 buffer...
注意事项
_cc_free_io_buffer 释放资源_CC_API_PUBLIC(void) _cc_free_io_buffer(_cc_io_buffer_t *io);
释放 IO Buffer 结构体及其关联的缓冲区资源。
参数说明
_cc_alloc_io_buffer 分配的 IO Buffer 指针示例代码
_cc_io_buffer_t *buffer = _cc_alloc_io_buffer(4096);
// 使用 buffer...
_cc_free_io_buffer(buffer);
注意事项
_CC_API_PUBLIC(void) _cc_realloc_read_buffer(_cc_io_buffer_t *io,int32_t limit);
动态调整读缓冲区的大小,支持扩容或缩容。
参数说明
示例代码
_cc_io_buffer_t *buffer = _cc_alloc_io_buffer(1024);
_cc_realloc_read_buffer(buffer, 2048); // 扩容读缓冲区
注意事项
_CC_API_PUBLIC(void) _cc_realloc_write_buffer(_cc_io_buffer_t *io,int32_t limit);
动态调整写缓冲区的大小,支持扩容或缩容。
参数说明
示例代码
_cc_io_buffer_t *buffer = _cc_alloc_io_buffer(1024);
_cc_realloc_write_buffer(buffer, 2048); // 扩容写缓冲区
注意事项
_CC_API_PUBLIC(int32_t) _cc_io_buffer_send(_cc_event_t *e, _cc_io_buffer_t *io, const byte_t *bytes, int32_t length);
将数据发送到 Socket,若 Socket 缓冲区已满,则写入 IO Buffer 的写缓冲区等待后续发送。
参数说明
返回值
_cc_last_error() 获取错误信息示例代码
byte_t data[] = "Hello, World!";
int32_t sent = _cc_io_buffer_send(event_mgr, buffer, data, strlen(data));
if (sent == -1) {
printf("发送失败,错误码: %d\n", _cc_last_error());
}
注意事项
_cc_io_buffer_flush_CC_API_PUBLIC(int32_t) _cc_io_buffer_flush(_cc_event_t *e, _cc_io_buffer_t *io);
将 IO Buffer 中的待发送数据推送到 Socket 缓冲区。适用于异步 I/O 场景,确保数据高效传输。
参数说明
返回值
_cc_last_error() 获取错误信息示例代码
int32_t flushed = _cc_io_buffer_flush(event_mgr, buffer);
if (flushed == -1) {
printf("推送失败,错误码: %d\n", _cc_last_error());
} else {
printf("成功推送 %d 字节数据\n", flushed);
}
注意事项
_CC_API_PUBLIC(uint64_t) _cc_timestamp(void);
获取当前时间戳
_CC_API_PUBLIC(int64_t) _cc_civil_to_days(int _year, int month, int day, int *day_of_week, int *day_of_year);
给定一个日期,返回自1970年1月1日以来的天数,一周中的一天[0-6,0是星期日],一年中的一天[0-365]。
参数:
_CC_API_PUBLIC(int) _cc_days_in_month(int year, int month);
给定一个年月,返回月中的天数[28、30、31]?
参数:
返回值: 月中的天数
_CC_API_PUBLIC(int) _cc_day_of_year(int year, int month, int day);
给定一个日期,返回自1970年1月1日以来的天数,一年中的一天[0-365]?
参数:
返回值: 一年中的第几天
_CC_API_PUBLIC(int) _cc_day_of_week(int year, int month, int day);
给定一个日期,返回自1970年1月1日以来的天数,一周中的一天[0-6,0是星期日]?
参数:
返回值: 星期几
_CC_API_PUBLIC(void) _cc_sleep(uint32_t ms);
睡眠
参数:
_CC_API_PUBLIC(void) _cc_nsleep(uint64_t ns);
睡眠
参数:
_CC_API_PUBLIC(void) _cc_nsleep(uint64_t ns);
睡眠
参数:
_CC_API_PUBLIC(uint64_t) _cc_get_ticks(void);
用于获取系统启动后经过的毫秒数
_CC_API_PUBLIC(uint64_t) _cc_get_ticks_ns(void);
用于获取系统启动后经过的纳秒数
/* http://user_name:user_password@localhost/index.html?id=1&tid=2#top */
typedef struct _cc_url {
/* (eg: http,ftp,maito) */
struct {
uint32_t ident;
_cc_sds_t value;
} scheme;
/* is IPv6*/
bool_t ipv6;
/* (eg: port) */
uint32_t port;
/* (eg: localhost) */
_cc_sds_t host;
/* (eg: /v1/index.html) */
_cc_sds_t path;
/* (eg: /v1/index.html?id=1&tid=2#top) */
_cc_sds_t request;
/* (eg: id=1&tid=2) */
_cc_sds_t query;
/* (eg: top) */
_cc_sds_t fragment;
/* (eg: user_name) */
_cc_sds_t username;
/* (eg: user_password) */
_cc_sds_t password;
} _cc_url_t;
_CC_API_PUBLIC(bool_t) _cc_alloc_url(_cc_url_t *u, const tchar_t *url);
解析一个URL
参数:
_CC_API_PUBLIC(bool_t) _cc_free_url(_cc_url_t *u);
释放URL结构体的资源
参数:
使用的例子:
char_t *url = "http://libcc.cn/index.html?id=1&tid=2#top";
_cc_url_t u;
_cc_alloc_url(&u, url);
printf("%s :// %s : %d / %s #%s\n",u.scheme.value, u.host, u.port, u.request, u.fragment);
_cc_free_url(&u);
_CC_API_PUBLIC(int32_t) _cc_url_encode(const tchar_t *src, int32_t src_len, tchar_t *dst, int32_t dst_len);
URL 编码:将字符串编码为url编码,并将编码后的字符串写入dst
参数:
返回值: 编码后字符串长度
_CC_API_PUBLIC(int32_t) _cc_url_decode(const tchar_t *src, int32_t src_len, tchar_t *dst, int32_t dst_len);
URL 编码:将字符串编码为url编码,并将编码后的字符串写入dst
参数:
返回值: 解码后字符串长度
_CC_API_PUBLIC(int32_t) _cc_raw_url_encode(const tchar_t *src, int32_t src_len, tchar_t *dst, int32_t dst_len);
URL 编码:将字符串编码为url编码,并将编码后的字符串写入dst
参数:
返回值: 编码后字符串长度
_CC_API_PUBLIC(int32_t) _cc_raw_url_decode(const tchar_t *src, int32_t src_len, tchar_t *dst, int32_t dst_len);
URL 编码:将字符串编码为url编码,并将编码后的字符串写入dst
参数:
返回值: 解码后字符串长度
typedef struct _cc_sql_delegate _cc_sql_delegate_t;
typedef struct _cc_sql _cc_sql_t;
typedef struct _cc_sql_result _cc_sql_result_t;
struct _cc_sql_delegate {
/**/
_cc_sql_t *(*connect)(const tchar_t *);
/**/
bool_t (*disconnect)(_cc_sql_t *);
/**/
bool_t (*reset)(_cc_sql_t *, _cc_sql_result_t *);
/**/
bool_t (*step)(_cc_sql_t *, _cc_sql_result_t *);
/**/
bool_t (*execute)(_cc_sql_t *, const _cc_string_t *, _cc_sql_result_t **);
/**/
bool_t (*auto_commit)(_cc_sql_t *, bool_t);
/**/
bool_t (*begin_transaction)(_cc_sql_t *);
/**/
bool_t (*commit)(_cc_sql_t *);
/**/
bool_t (*rollback)(_cc_sql_t *);
/**/
bool_t (*next_result)(_cc_sql_t *, _cc_sql_result_t *);
/**/
bool_t (*free_result)(_cc_sql_t *, _cc_sql_result_t *);
/**/
int32_t (*get_num_fields)(_cc_sql_result_t *);
/**/
uint64_t (*get_num_rows)(_cc_sql_result_t *);
/**/
bool_t (*fetch)(_cc_sql_result_t *);
/**/
pvoid_t (*get_stmt)(_cc_sql_result_t *);
/**/
uint64_t (*get_last_id)(_cc_sql_t *, _cc_sql_result_t *);
/**/
bool_t (*bind)(_cc_sql_result_t *, int32_t, const void *, size_t, uint8_t);
/**/
int32_t (*get_int)(_cc_sql_result_t *, int32_t);
/**/
int64_t (*get_int64)(_cc_sql_result_t *, int32_t);
/**/
float64_t (*get_float)(_cc_sql_result_t *, int32_t);
/**/
size_t (*get_string)(_cc_sql_result_t *, int32_t, tchar_t*, size_t);
/**/
size_t (*get_blob)(_cc_sql_result_t *, int32_t, byte_t **);
/**/
bool_t (*get_datetime)(_cc_sql_result_t *, int32_t, struct tm*);
};
_CC_API_PUBLIC(bool_t) _cc_register_mysql(_cc_sql_delegate_t *delegator);
初始化mysql
_CC_API_PUBLIC(bool_t) _cc_register_sqlsvr(_cc_sql_delegate_t *delegator);
初始化sql server
_CC_API_PUBLIC(bool_t) _cc_register_sqlite(_cc_sql_delegate_t *delegator);
初始化sqlite3
_CC_API_PUBLIC(bool_t) _cc_register_oci8(_cc_sql_delegate_t *delegator);
初始化 OCI8
使用的例子:
_cc_sql_delegate_t mysql;
_cc_register_sqlite(&mysql);
_cc_sql_t *conn = mysql.connect("mysql://root:123654asd@127.0.0.1:3306/test");
if (conn) {
printf("connection succed\n");
mysql.disconnect(conn);
} else {
printf("connection failed\n");
}
以下函数组提供了从 JSON 对象/数组中提取各种类型数据的标准方法:
对象字段访问
// 获取JSON对象中的整型 (返回0如果字段不存在或类型不匹配)
int64_t _cc_json_object_find_number(const _cc_json_t *ctx, const tchar_t *keyword);
// 获取JSON对象中的浮点数 (返回0.0如果字段不存在或类型不匹配)
float64_t _cc_json_object_find_float(const _cc_json_t *ctx, const tchar_t *keyword);
// 获取JSON对象中的字符串 (返回NULL如果字段不存在或类型不匹配)
const _cc_sds_t _cc_json_object_find_string(const _cc_json_t *ctx, const tchar_t *keyword);
// 获取JSON对象中的数组 (返回NULL如果字段不存在或类型不匹配)
_cc_array_t _cc_json_object_find_array(const _cc_json_t *ctx, const tchar_t *keyword);
// 获取JSON对象中的子对象 (返回NULL如果字段不存在或类型不匹配)
const _cc_rbtree_t *_cc_json_object_find_object(const _cc_json_t *ctx, const tchar_t *keyword);
// 获取JSON对象中的布尔值 (返回false如果字段不存在或类型不匹配)
bool_t _cc_json_object_find_boolean(const _cc_json_t *ctx, const tchar_t *keyword);
数组元素访问
// 获取JSON数组中的整型 (索引越界返回0)
int64_t _cc_json_array_find_number(const _cc_json_t *ctx, const uint32_t index);
// 获取JSON数组中的浮点数 (索引越界返回0.0)
float64_t _cc_json_array_find_float(const _cc_json_t *ctx, const uint32_t index);
// 获取JSON数组中的字符串 (索引越界返回NULL)
const _cc_sds_t _cc_json_array_find_string(const _cc_json_t *ctx, const uint32_t index);
// 获取JSON数组中的子对象 (索引越界返回NULL)
const _cc_rbtree_t* _cc_json_array_find_object(const _cc_json_t *ctx, const uint32_t index);
// 获取JSON数组中的子数组 (索引越界返回NULL)
_cc_array_t _cc_json_array_find_array(const _cc_json_t *ctx, const uint32_t index);
// 获取JSON数组中的布尔值 (索引越界返回false)
bool_t _cc_json_array_find_boolean(const _cc_json_t *ctx, const uint32_t index);
使用示例
// 解析JSON对象
_cc_json_t* json = _cc_json_parse("{\"name\":\"John\", \"age\":30}", 18);
// 获取字段值
const _cc_sds_t name = _cc_json_object_find_string(json, "name");
int64_t age = _cc_json_object_find_number(json, "age");
// 处理数组
_cc_array_t arr = _cc_json_object_find_array(json, "items");
if (arr) {
for (int32_t i = 0; i < _cc_array_length(arr); i++) {
_cc_json_t *it = (_cc_json_t*)_cc_array_value(arr,i);
//....
}
}
_cc_free_json(json);
注意事项
_CC_API_PUBLIC(_cc_json_t *) _cc_json_from_file(const tchar_t *file);
从文件系统加载并解析 JSON 数据,支持 UTF-8 编码。
参数说明
返回值
示例代码
_cc_json_t* config = _cc_json_from_file("config.json");
if (!config) {
printf("无法加载配置文件\n");
return;
}
// 使用 config...
_cc_free_json(config);
注意事项
_cc_free_json 释放_CC_API_PUBLIC(_cc_json_t *) _cc_json_parse(const tchar_t *src, size_t length);
解析内存中的 JSON 字符串,构建对象树。
参数说明
返回值
示例代码
const tchar_t* json_str = "{\"key\":\"value\"}";
_cc_json_t* obj = _cc_json_parse(json_str, 0);
if (!obj) {
printf("JSON 解析失败\n");
return;
}
// 使用 obj...
_cc_free_json(obj);
注意事项
_cc_free_json 释放_CC_API_PUBLIC(void) _cc_json_dump(_cc_json_t *ctx, _cc_buf_t* buf);
将 JSON 对象树序列化为字符串,支持格式化输出。
参数说明
示例代码
_cc_buf_t buf;
_cc_json_dump(json_obj, &buf);
printf("JSON: %.*s\n", (int)buf.len, buf.data);
_cc_free_buf(&buf);
_CC_API_PUBLIC(_cc_json_t *) _cc_json_alloc_object(byte_t type, const tchar_t *keyword);
创建一个JSON对象结构体
参数:
JSON Type:
/*
* JSON Types:
*/
enum _CC_JSON_TYPES_ {
_CC_JSON_NULL_ = 0, //空类型
_CC_JSON_BOOLEAN_, //布尔型
_CC_JSON_FLOAT_, //浮点型
_CC_JSON_INT_, //整数型
_CC_JSON_OBJECT_, //对象
_CC_JSON_ARRAY_, //数组
_CC_JSON_STRING_ //字符串
};
_CC_API_PUBLIC(void) _cc_free_json(_cc_json_t *ctx);
释放JSON所有资源
参数:
XML 文档在内存中以树形结构表示,每个节点包含以下字段:
typedef struct _cc_xml {
/* 节点类型,见 _CC_XML_TYPES_ 枚举 */
byte_t type;
/* 节点名称(标签名) */
_cc_sds_t name;
/* 节点内容联合体 */
union {
_cc_sds_t uni_comment; // 注释内容
_cc_sds_t uni_doctype; // DOCTYPE 声明
_cc_xml_context_t uni_context; // 文本内容
_cc_list_iterator_t uni_child; // 子节点列表
} element;
/* 兄弟节点链表指针 */
_cc_list_iterator_t lnk;
/* 属性表(键值对) */
_cc_rbtree_t attr;
} _cc_xml_t;
节点类型
/**
* XML 节点类型枚举
*/
enum _CC_XML_TYPES_ {
_CC_XML_NULL_ = 0, // 空节点
_CC_XML_COMMENT_, // 注释节点
_CC_XML_CONTEXT_, // 文本内容节点
_CC_XML_DOCTYPE_, // 文档类型声明
_CC_XML_CHILD_ // 普通元素节点
};
内存管理
_cc_alloc_xml_element 创建_cc_free_xml 释放_CC_API_PUBLIC(_cc_xml_t*) _cc_xml_from_file(const tchar_t* file);
加载并解析 XML 文件,支持 UTF-8 编码。
参数说明
返回值
示例代码
_cc_xml_t* doc = _cc_xml_from_file("config.xml");
if (!doc) {
printf("XML 解析失败\n");
return;
}
// 使用 doc...
_cc_free_xml(doc);
注意事项
_cc_free_xml 释放_CC_API_PUBLIC(_cc_xml_t *) _cc_xml_parse(const tchar_t *src, size_t length);
解析内存中的 XML 字符串,构建对象树。
参数说明
返回值
示例代码
const tchar_t* xml_str = "- test
";
_cc_xml_t* doc = _cc_xml_parse(xml_str, 0);
if (!doc) {
printf("XML 解析失败\n");
return;
}
// 使用 doc...
_cc_free_xml(doc);
注意事项
_cc_free_xml 释放_CC_API_PUBLIC(void) _cc_xml_dump(_cc_xml_t *ctx, _cc_buf_t* buf);
XML序列化字符串
参数:
_CC_API_PUBLIC(_cc_xml_t*) _cc_alloc_xml_element(byte_t type);
创建一个XML对象结构体
参数:
JSON Type:
/**
* @brief XML Types:
*/
enum _CC_XML_TYPES_ {
_CC_XML_NULL_ = 0, // 空
_CC_XML_COMMENT_, // 注解
_CC_XML_CONTEXT_, // 内容
_CC_XML_DOCTYPE_, // doctype
_CC_XML_CHILD_ // 子节点
};
_CC_API_PUBLIC(void) _cc_free_xml(_cc_xml_t* ctx);
释放XML所有资源
参数:
_CC_API_PUBLIC(bool_t) _cc_xml_element_append(_cc_xml_t* ctx, _cc_xml_t* child);
XML附加子节点
参数:
_CC_API_PUBLIC(_cc_xml_t*) _cc_xml_element_find(_cc_xml_t* ctx, tchar_t* name);
XML查找,通过nodeName 查找
参数:
_CC_API_PUBLIC(_cc_xml_t*) _cc_xml_element_first_child(_cc_xml_t* ctx);
获取第一个子节点
参数:
_CC_API_PUBLIC(_cc_xml_t*) _cc_xml_element_next_child(_cc_xml_t* ctx);
获取下一个子节点
参数:
_CC_API_PUBLIC(const _cc_sds_t) _cc_xml_element_text(_cc_xml_t* ctx);
获取节点文本内容
参数:
_CC_API_PUBLIC(const _cc_sds_t) _cc_xml_element_attr(_cc_xml_t* ctx, const tchar_t* keyword);
获取节点上的属性值
参数:
返回值: 字符串
_CC_API_PUBLIC(bool_t) _cc_xml_element_set_attr(_cc_xml_t* ctx, const tchar_t* keyword, const tchar_t* fmt, ...);
设置节点属性
参数:
INI 配置在内存中以键值对和分节(Section)的形式组织,结构如下:
/*
* INI Types:
*/
enum _CC_INI_TYPES_ {
_CC_INI_NULL_ = 0, // 空类型
_CC_INI_SECTION_, // 分节类型
_CC_INI_BOOLEAN_, // 布尔类型
_CC_INI_FLOAT_, // 浮点类型
_CC_INI_INT_, // 整数类型
_CC_INI_STRING_ // 字符串类型
};
typedef struct _cc_ini {
/* 节点类型 */
byte_t type;
/* 节点名称(Section 名或键名) */
_cc_sds_t name;
/* 节点值联合体 */
union {
bool_t uni_boolean; // 布尔值
int64_t uni_int; // 整数值
float64_t uni_float; // 浮点值
_cc_sds_t uni_string; // 字符串值
_cc_rbtree_t uni_object; // 子 Section
} element;
/* 同级节点链表指针 */
_cc_rbtree_iterator_t lnk;
} _cc_ini_t;
内存管理
_cc_ini_from_file)创建_cc_free_ini 释放_CC_API_PUBLIC(_cc_ini_t*) _cc_ini_from_file(const tchar_t* file);
加载并解析 INI 配置文件,支持标准 INI 格式。
参数说明
返回值
示例代码
_cc_ini_t* config = _cc_ini_from_file("config.ini");
if (!config) {
printf("INI 解析失败\n");
return;
}
// 使用 config...
_cc_free_ini(config);
注意事项
_cc_free_ini 释放_CC_API_PUBLIC(_cc_ini_t *) _cc_ini_parse(const tchar_t *src, size_t length);
解析内存中的 INI 格式字符串,构建配置树。
参数说明
返回值
示例代码
const tchar_t* ini_str = "[Section]\nkey=value";
_cc_ini_t* config = _cc_ini_parse(ini_str, 0);
if (!config) {
printf("INI 解析失败\n");
return;
}
// 使用 config...
_cc_free_ini(config);
注意事项
_cc_free_ini 释放_CC_API_PUBLIC(void) _cc_free_ini(_cc_ini_t* ctx);
释放 INI 配置对象及其所有关联资源(包括子 Section 和键值对)。
参数说明
示例代码
_cc_ini_t* config = _cc_ini_from_file("config.ini");
// 使用 config...
_cc_free_ini(config); // 安全释放
注意事项
_CC_API_PUBLIC(void) _cc_ini_dump(_cc_ini_t *ctx, _cc_buf_t* buf);
将 INI 配置对象序列化为字符串并写入缓冲区。
参数说明
示例代码
_cc_buf_t buf;
_cc_ini_dump(config, &buf);
printf("INI content: %s\n", buf.data);
_cc_buf_free(&buf);
注意事项
_CC_API_PUBLIC(_cc_ini_t*) _cc_ini_find(_cc_ini_t* ctx, const tchar_t* name);
查找 INI 配置中的 Section 或键值。
参数说明
返回值
示例代码
// 查找 "database"
_cc_ini_t* database = _cc_ini_find(config, "database");
if (database) {
// 查找 "port"
_cc_ini_t* port_node = _cc_ini_find(database, "port");
if (port_node) {
printf("Found port: %ld\n", port_node->element.uni_int);
}
}
注意事项
_CC_API_PUBLIC(_cc_sds_t) _cc_ini_find_string(_cc_ini_t* ctx, const tchar_t* name);
INI 查找属性字符串值
参数:
// 日志严重级别枚举
enum {
_CC_LOG_LEVEL_EMERG_ = 0, // 系统不可用(最高级别)
_CC_LOG_LEVEL_ALERT_, // 需要立即采取行动
_CC_LOG_LEVEL_CRIT_, // 关键错误
_CC_LOG_LEVEL_ERROR_, // 一般错误
_CC_LOG_LEVEL_WARNING_, // 警告信息
_CC_LOG_LEVEL_NOTICE_, // 正常但重要的事件
_CC_LOG_LEVEL_INFO_, // 信息性消息
_CC_LOG_LEVEL_DEBUG_ // 调试信息(最低级别)
};
等级说明
使用建议
_CC_API_PUBLIC(void) _cc_loggerW_format(const tchar_t *file, int line, uint8_t level, const wchar_t* fmt, ...);
宽字符版本日志输出函数,支持格式化字符串和可变参数。
参数说明
__FILE__ 宏__LINE__ 宏示例代码
_cc_loggerW_format(__FILE__, __LINE__, _CC_LOG_LEVEL_ERROR_,
L"Failed to open file: %s", L"config.txt");
注意事项
_CC_UNICODE_ 宏时可用_CC_API_PUBLIC(void) _cc_loggerA_format(const tchar_t *file, int line, uint8_t level, const char_t* fmt, ...);
多字节字符版本日志输出函数,支持格式化字符串和可变参数。
参数说明
__FILE__ 宏__LINE__ 宏示例代码
_cc_loggerA_format(__FILE__, __LINE__, _CC_LOG_LEVEL_ERROR_,
"Failed to open file: %s", "config.txt");
注意事项
_CC_UNICODE_ 宏时使用此版本/**/
#ifdef _CC_UNICODE_
#define _cc_logger_format _cc_loggerW_format
#define _cc_logger(LEVEL, MSG) _cc_loggerW(_CL(_CC_FILE_), _CC_LINE_, LEVEL, MSG, wcslen(MSG))
#define _cc_static_logger(LEVEL, MSG) _cc_loggerW(_CL(_CC_FILE_), _CC_LINE_, LEVEL, MSG, sizeof(MSG) - 1)
#define _cc_logger_warin _cc_loggerW_warin
#define _cc_logger_debug _cc_loggerW_debug
#define _cc_logger_info _cc_loggerW_info
#define _cc_logger_error _cc_loggerW_error
#define _cc_logger_alert _cc_loggerW_alert
#define _cc_logger_syslog _cc_syslogW
#else
#define _cc_logger_format _cc_loggerA_format
#define _cc_logger(LEVEL, MSG) _cc_loggerA(_CC_FILE_, _CC_LINE_, LEVEL, MSG, strlen(MSG))
#define _cc_static_logger(LEVEL, MSG) _cc_loggerA(_CC_FILE_, _CC_LINE_, LEVEL, MSG, sizeof(MSG) - 1)
#define _cc_logger_warin _cc_loggerA_warin
#define _cc_logger_debug _cc_loggerA_debug
#define _cc_logger_info _cc_loggerA_info
#define _cc_logger_error _cc_loggerA_error
#define _cc_logger_alert _cc_loggerA_alert
#define _cc_logger_syslog _cc_syslogA
#endif
宏说明
示例代码
// 动态字符串示例
_cc_logger_error(("Error code: %d", errno));
// 静态字符串示例
_cc_static_logger(_CC_LOG_LEVEL_INFO_, "System initialized");
// 快捷宏示例
_cc_logger_debug(("Debug value: %f", debug_value));
_cc_logger_alert(("Critical alert!"));
性能建议
Syslog(系统日志)是一种用于在互联网协议(TCP/IP)网络中传递记录消息的标准协议,它采用主从式架构,允许设备和应用程序将事件消息发送到中央日志服务器进行集中管理和分析
// Facility
enum {
_CC_LOG_FACILITY_KERN_ = 0, // Kernel messages
_CC_LOG_FACILITY_USER_, // User-level messages
_CC_LOG_FACILITY_MAIL_, // Mail system
_CC_LOG_FACILITY_DAEMON_, // System daemons
_CC_LOG_FACILITY_AUTH_, // Security/authentication messages
_CC_LOG_FACILITY_SYSLOG_, // Messages generated internally by syslogd
_CC_LOG_FACILITY_LPR_, // Line printer subsystem
_CC_LOG_FACILITY_NEWS_, // Network news subsystem
_CC_LOG_FACILITY_UUCP_, // UUCP subsystem
_CC_LOG_FACILITY_CRON_, // Clock daemon
_CC_LOG_FACILITY_AUTHPRIV_, // Security/authentication messages
_CC_LOG_FACILITY_FTP_, // FTP daemon
_CC_LOG_FACILITY_NTP_, // NTP subsystem
_CC_LOG_FACILITY_SECURITY_, // Log audit
_CC_LOG_FACILITY_CONSOLE_, // Log console
// //Locally-used facilities
_CC_LOG_FACILITY_LOCAL0_ = 16,
_CC_LOG_FACILITY_LOCAL1_,
_CC_LOG_FACILITY_LOCAL2_,
_CC_LOG_FACILITY_LOCAL3_,
_CC_LOG_FACILITY_LOCAL4_,
_CC_LOG_FACILITY_LOCAL5_,
_CC_LOG_FACILITY_LOCAL6_,
_CC_LOG_FACILITY_LOCAL7_ = 23 // Memory tracking
};
// Severity Level
enum {
_CC_LOG_LEVEL_EMERG_ = 0, // System is unusable
_CC_LOG_LEVEL_ALERT_, // Action must be taken immediately
_CC_LOG_LEVEL_CRIT_, // Critical
_CC_LOG_LEVEL_ERROR_, // Error
_CC_LOG_LEVEL_WARNING_, // Warning
_CC_LOG_LEVEL_NOTICE_, // Normal but significant condition
_CC_LOG_LEVEL_INFO_, // Informational messages
_CC_LOG_LEVEL_DEBUG_ // Debug-level messages
};
_CC_API_PUBLIC(void) _cc_open_syslog(uint8_t facility, const tchar_t *app_name, const tchar_t *ip, const uint16_t port);
初始化 Syslog 远程服务连接,使用 UDP 协议将日志消息发送到指定的日志服务器。
参数说明
示例代码
_cc_open_syslog(_CC_LOG_FACILITY_USER_, "my_app", "192.168.1.100", 514);
注意事项
_cc_close_syslog 关闭连接_CC_API_PUBLIC(void) _cc_close_syslog(void);
关闭 Syslog 远程服务连接,停止日志发送。
示例代码
_cc_open_syslog(_CC_LOG_FACILITY_USER_, "my_app", "192.168.1.100", 514);
// 发送日志...
_cc_close_syslog();
注意事项
_cc_open_syslog 初始化_CC_API_PUBLIC(size_t) _cc_syslog_header(uint8_t pri, tchar_t *buffer, size_t buffer_length);
生成符合 RFC 标准的 Syslog 消息头。
参数说明
Facility × 8 + Severity返回值
示例代码
tchar_t header[1024];
size_t len = _cc_syslog_header(_CC_LOG_FACILITY_USER_ * 8 + _CC_LOG_LEVEL_INFO, header, 1024);
if (len == 0) {
printf("Failed to format syslog header\n");
}
注意事项
_cc_syslog_send 发送_CC_API_PUBLIC(void) _cc_syslog_send(const uint8_t *msg, size_t length);
通过 UDP 协议发送格式化后的 Syslog 消息到日志服务器。
参数说明
示例代码
tchar_t header[1024];
size_t len = _cc_syslog_header(_CC_LOG_FACILITY_USER_ * 8 + _CC_LOG_LEVEL_INFO, header, 1024);
if (len > 0) {
strcat(header + len , "Hello, syslog!", 14);
_cc_syslog_send((const uint8_t *)header, len + 14);
}
注意事项
_cc_open_syslog 初始化连接