【C语言开源库】C语言必备实用第三方库Melon(包括数据结构算法)_c melon

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

return 0;
}


##### mln\_string\_strcmp



int mln_string_strcmp(mln_string_t *s1, mln_string_t *s2);


描述:比较`s1`与`s2`中数据的大小。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_const\_strcmp



int mln_string_const_strcmp(mln_string_t *s1, char *s2);


描述:比较`s1`所记录的数据与`s2`的大小。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_strncmp



int mln_string_strncmp(mln_string_t *s1, mln_string_t *s2, mln_u32_t n);


描述:比较`s1`与`s2`的前`n`个字节的大小。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_const\_strncmp



int mln_string_const_strncmp(mln_string_t *s1, char *s2, mln_u32_t n);


描述:比较`s1`所记录的数据与`s2`的前`n`个字节的大小。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_strcasecmp



int mln_string_strcasecmp(mln_string_t *s1, mln_string_t *s2);


描述:比较`s1`与`s2`数据的大小,且忽略大小写。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_const\_strcasecmp



int mln_string_const_strcasecmp(mln_string_t *s1, char *s2);


描述:比较`s1`所记录的数据与`s2`的大小,且忽略大小写。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_const\_strncasecmp



int mln_string_const_strncasecmp(mln_string_t *s1, char *s2, mln_u32_t n);


描述:比较`s1`所记录的数据与`s2`的前`n`个字节的大小,且忽略大小写。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_strncasecmp



int mln_string_strncasecmp(mln_string_t *s1, mln_string_t *s2, mln_u32_t n);


描述:比较`s1`与`s2`所记录数据的前`n`个字节的大小,且忽略大小写。


返回值:


* -1 - `s1`比`s2`小
* 1 - `s1`比`s2`大
* 0 - 二者相同


##### mln\_string\_strstr



char *mln_string_strstr(mln_string_t *text, mln_string_t *pattern);


描述:匹配`text`所记录的数据中与`pattern`中数据一样的起始地址。


返回值:若匹配成功,则返回`text`的`data`成员所指向地址中的对应地址;否则返回`NULL`。


##### mln\_string\_const\_strstr



char *mln_string_const_strstr(mln_string_t *text, char *pattern);


描述:匹配`text`所记录的数据中与`pattern`一样的起始地址。


返回值:若匹配成功,则返回`text`的`data`成员所指向地址中的对应地址;否则返回`NULL`。


##### mln\_string\_new\_strstr



mln_string_t *mln_string_new_strstr(mln_string_t *text, mln_string_t *pattern);


描述:与`mln_string_strstr`功能一致,但返回的是由`mln_string_t`结构包装后的字符串。


返回值:成功则返回`mln_string_t`指针,否则返回`NULL`。


##### mln\_string\_new\_const\_strstr



mln_string_t *mln_string_new_const_strstr(mln_string_t *text, char *pattern);


描述:与`mln_string_const_strstr`功能一致,但返回的是由`mln_string_t`结构包装后的字符串。


返回值:成功则返回`mln_string_t`指针,否则返回`NULL`。


##### mln\_string\_kmp



char *mln_string_kmp(mln_string_t *text, mln_string_t *pattern);


描述:与`mln_string_strstr`功能一致,但是是由KMP算法实现的。KMP算法适用场景是,`text`中有较多与`pattern`前缀相同的字符串的情况。例如: `text`中包含`aaaaaaaaaabc`,`pattern`中包含`ab`,此时,KMP算法性能将高于朴素算法。


返回值:若匹配成功,则返回`text`的`data`成员所指向地址中的对应地址;否则返回`NULL`。


##### mln\_string\_const\_kmp



char *mln_string_const_kmp(mln_string_t *text, char *pattern);


描述:与`mln_string_kmp`功能一致,但`pattern`为字符指针类型。


返回值:若匹配成功,则返回`text`的`data`成员所指向地址中的对应地址;否则返回`NULL`。


##### mln\_string\_new\_kmp



mln_string_t *mln_string_new_kmp(mln_string_t *text, mln_string_t *pattern);


描述:与`mln_string_kmp`功能一致,但返回的是由`mln_string_t`结构包装后的数据。


返回值:成功则返回`mln_string_t`指针,失败则返回`NULL`。


##### mln\_string\_new\_const\_kmp



mln_string_t *mln_string_new_const_kmp(mln_string_t *text, char *pattern);


描述:与`mln_string_const_kmp`功能一致,但返回的是由`mln_string_t`结构包装后的数据。


返回值:成功则返回`mln_string_t`指针,失败则返回`NULL`。


##### mln\_string\_slice



mln_string_t *mln_string_slice(mln_string_t *s, const char *sep_array/ended by \0/);


描述:`seq_array`是一个字符数组且以0结尾,该数组的每一个字符都是一个分隔标志。函数会扫描`s`的数据部分,当数据中遇到`seq_array`中的任意一个字符时都会被进行分割,连续遇到多个时仅分割一次,且分割后,分隔符不会出现在被分割后的字符串中。


返回值:成功则返回`mln_string_t`数组,否则返回`NULL`。数组的最后一个元素的`len`为`0`,且`data`为`NULL`。


举例:



int main(void)
{
mln_string_t s = mln_string(“abc-def-=ghi”);
mln_string_t *str, *arr = mln_string_slice(&s, “-=”);
for (str = arr; str->data != NULL; ++str) {
mln_log(debug, “%S”, str);
}
mln_string_slice_free(arr);
return 0;
}


##### mln\_string\_slice\_free



void mln_string_slice_free(mln_string_t *array);


描述:释放由`mln_string_slice`函数创建的`mln_string_t`数组。


返回值:无


##### mln\_string\_strcat



mln_string_t *mln_string_strcat(mln_string_t *s1, mln_string_t *s2);


描述:创建一个新的`mln_string_t`结构,其数据为`s1`和`s2`依此顺序拼接后的结果。


返回值:成功则返回`mln_string_t`指针,否则返回`NULL`。


##### mln\_string\_pool\_strcat



mln_string_t *mln_string_pool_strcat(mln_alloc_t *pool, mln_string_t *s1, mln_string_t *s2);


描述:与`mln_string_strcat`功能一致,仅新的结构所使用内存由`pool`指向的内存池分配。


返回值:成功则返回`mln_string_t`指针,否则返回`NULL`。


### 双向链表


#### 头文件



#include “mln_defs.h”


#### 函数/宏


##### MLN\_CHAIN\_FUNC\_DECLARE



MLN_CHAIN_FUNC_DECLARE(prefix,type,ret_attr,func_attr);


描述:本宏用于对双向链表的添加操作和删除操作函数进行声明,其中:


* `prefix`:为两个函数名的前缀,这是为了允许在一个源文件内为多个双向链表进行函数声明。
* `type`:链表节点的类型
* `ret_attr`:两个函数的操作域类型和返回值类型
* `func_attr`:对函数参数的约束(仅限于Linux中),若无则留空即可


##### MLN\_CHAIN\_FUNC\_DEFINE



MLN_CHAIN_FUNC_DEFINE(prefix,type,ret_attr,prev_ptr,next_ptr);

ret_attr prefix##_chain_add(type **head, type **tail, type *node);
ret_attr prefix##_chain_del(type **head, type **tail, type *node);


描述:本宏用于定义双向链表的添加和删除操作函数,其中:


* `prefix`:为两个函数名的前缀,这是为了允许在一个源文件内为多个双向链表进行函数声明。
* `type`:链表节点的类型
* `ret_attr`:两个函数的操作域类型和返回值类型
* `prev_ptr`:链表节点中指向前一节点的指针名
* `next_ptr`:链表节点中指向后一节点的指针名


`chain_add`和`chain_del`分别为添加和删除节点函数,两个函数的参数为:


* `head`:二级指针,用于在操作函数内对头指针自动修改
* `tail`:二级指针,用于在操作函数内对尾指针自动修改
* `node`:被加入的节点指针,其前后指向的指针可能会被修改


#### 示例



#include <stdio.h>
#include <stdlib.h>
#include “mln_defs.h”

typedef struct chain_s {
int val;
struct chain_s *prev;
struct chain_s *next;
} chain_t;

MLN_CHAIN_FUNC_DECLARE(test, chain_t, static inline void, );
MLN_CHAIN_FUNC_DEFINE(test, chain_t, static inline void, prev, next);

int main(void)
{
int i;
chain_t *head = NULL, *tail = NULL, *c;

for (i = 0; i < 10; ++i) {
c = (chain_t *)malloc(sizeof(chain_t));
if (c == NULL) {
fprintf(stderr, “malloc failed.\n”);
return -1;
}
c->val = i;
c->prev = c->next = NULL;
test_chain_add(&head, &tail, c);
}

for (c = head; c != NULL; c = c->next) {
printf(“%d\n”, c->val);
}
return 0;
}


### 栈


#### 头文件



#include “mln_stack.h”


#### 函数/宏


##### mln\_stack\_init



mln_stack_t *mln_stack_init(struct mln_stack_attr *attr);

struct mln_stack_attr {
stack_free free_handler;//栈节点数据释放函数
stack_copy copy_handler;//栈节点数据复制函数
mln_u32_t cache:1;//是否缓存栈节点结构
};

typedef void (*stack_free)(void *);
typedef void *(*stack_copy)(void *, void *);


描述:


初始化栈结构。


`free_handler`:是入栈数据的释放函数,由于入栈数据可能为自定义数据结构,因此若需释放,可对此进行设置否则置`NULL`。


`copy_handler`:复制栈节点数据。


`cache`:是否缓存**全部**栈节点结构内存以提升效率(非用户数据)。


`stack_free`的参数为用户自定义数据的数据结构指针。


`stack_copy`的参数分别为:被复制的栈节点数据的数据结构指针 和 `mln_stack_dup`函数的第二个参数(即用户自定义数据),这个回调函数仅在`mln_stack_dup`函数中被调用。


返回值:成功则返回栈指针,否则为`NULL`


##### mln\_stack\_destroy



void mln_stack_destroy(mln_stack_t *st);


描述:销毁栈结构,并释放栈节点内数据资源。


返回值:无


##### mln\_stack\_push



int mln_stack_push(mln_stack_t *st, void *data);


描述:将数据`data`压入栈`st`中。


返回值:成功返回`0`,否则返回`-1`


##### mln\_stack\_pop



void *mln_stack_pop(mln_stack_t *st);


描述:将栈`st`的栈顶元素数据弹出。


返回值:若栈内无元素则为`NULL`,否则为栈节点内的数据指针


##### mln\_stack\_empty



mln_stack_empty(s)


描述:判断栈是否为空。


返回值:空为`非0`,否则为`0`


##### mln\_stack\_top



mln_stack_top(st)


描述:获取栈顶元素数据。


返回值:若栈`st`为空则返回`NULL`,否则为栈顶节点内的数据指针


##### mln\_stack\_dup



mln_stack_t *mln_stack_dup(mln_stack_t *st, void *udata);


描述:完全复制栈`st`。`udata`为用户提供的额外数据。


返回值:若成功则返回新栈指针,否则返回`NULL`


##### mln\_stack\_scan\_all



int mln_stack_scan_all(mln_stack_t *st, stack_scan scanner, void *data);

typedef int (*stack_scan)(void *, void *);


描述:


从栈顶向栈底遍历栈`st`的每一个栈内元素数据。`scanner`为数据访问函数,`data`为遍历时的额外用户数据。


`stack_scan`有两个参数,分别为:栈节点内数据指针 和 `data`参数。


返回值:


* `mln_stack_scan_all`:全部遍历完则返回`0`,否则返回`-1`
* `stack_scan`:若想中断遍历则返回`小于0`的值,否则返回值`大于等于0`


### 队列


#### 头文件



#include “mln_queue.h”


#### 函数/宏


##### mln\_queue\_init



mln_queue_t *mln_queue_init(struct mln_queue_attr *attr);

struct mln_queue_attr {
mln_uauto_t qlen; //队列长度
queue_free free_handler; //队列节点数据的释放函数
};
typedef void (*queue_free)(void *);


描述:创建队列。


本队列为固定长度队列,因此`attr.qlen`就是队列的长度。`free_handler`为释放函数,用于释放队列内每个成员中的数据。若不需要释放则置`NULL`即可。


释放函数的参数即为队列每个成员的数据结构指针。


返回值:成功则返回`mln_queue_t`类型的队列指针,失败则返回`NULL`


##### mln\_queue\_destroy



void mln_queue_destroy(mln_queue_t *q);


描述:销毁队列。


队列销毁时,会根据`free_handler`的设置而自动释放队列成员的数据。


返回值:无


##### mln\_queue\_append



int mln_queue_append(mln_queue_t *q, void *data);


描述:将数据`data`追加进队列`q`的末尾。


返回值:若队列已满则返回`-1`,成功返回`0`


##### mln\_queue\_get



void *mln_queue_get(mln_queue_t *q);


描述:获取队首成员的数据。


返回值:成功则返回数据指针,若队列为空则返回`NULL`


##### mln\_queue\_remove



void mln_queue_remove(mln_queue_t *q);


描述:删除队首元素,但不释放资源。


返回值:无


##### mln\_queue\_search



void *mln_queue_search(mln_queue_t *q, mln_uauto_t index);


描述:查找并返回从队列`q`队首开始的第`index`成员的数据,下标从0开始。


返回值:成功则返回数据指针,否则为`NULL`


##### mln\_queue\_free\_index



void mln_queue_free_index(mln_queue_t *q, mln_uauto_t index);


描述:释放队列`q`内指定下标`index`的成员,并根据`free_handler`释放其数据。


返回值:无


##### mln\_queue\_scan\_all



int mln_queue_scan_all(mln_queue_t *q, queue_scan scan_handler, void *udata);

typedef int (*queue_scan)(void *, void *);


描述:遍历每一个队列成员。


`udata`为辅助遍历的自定义结构指针,若不需要可置`NULL`。


`scan_handler`的两个参数分别为:`成员数据`,`udata`。


返回值:遍历完成返回`0`,被中断则返回`-1`


##### mln\_queue\_empty



mln_queue_empty(q)


描述:判断队列`q`是否为空队列。


返回值:空则为`非0`,否则为`0`


##### mln\_queue\_full



mln_queue_full(q)


描述:判断队列是否已满。


返回值:满则为`非0`,否则为`0`


##### mln\_queue\_length



mln_queue_length(q)


描述:获取队列`q`的总长度。


返回值:无符号整型长度值


##### mln\_queue\_element



mln_queue_element(q)


描述:获取队列`q`中当前的成员数量。


返回值:无符号整型数量值


#### 示例



#include <stdio.h>
#include <stdlib.h>
#include “mln_core.h”
#include “mln_log.h”
#include “mln_queue.h”

int main(int argc, char *argv[])
{
int i = 10;
mln_queue_t *q;
struct mln_queue_attr qattr;
struct mln_core_attr cattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = NULL;
if (mln\_core\_init(&cattr) < 0) {
    fprintf(stderr, "init failed\n");
    return -1;
}

qattr.qlen = 10;
qattr.free_handler = NULL;
q = mln\_queue\_init(&qattr);
if (q == NULL) {
    mln\_log(error, "queue init failed.\n");
    return -1;
}
mln\_queue\_append(q, &i);
mln\_log(debug, "%d\n", \*(int \*)mln\_queue\_get(q));
mln\_queue\_destroy(q);

return 0;

}


内存池


Melon中,内存池分为两类:


* 堆内存
* 共享内存


其中,共享内存内存池只允许主子进程之间共享数据(兄弟进程之间也共享)。即使用时,由主进程创建共享内存内存池,然后创建子进程。


头文件



#include “mln_alloc.h”


函数


mln\_alloc\_init



mln_alloc_t *mln_alloc_init(void);


描述:创建堆内存内存池。


返回值:成功则返回内存池结构指针,否则返回`NULL`


mln\_alloc\_shm\_init



mln_alloc_t *mln_alloc_shm_init(mln_size_t size);


描述:创建共享内存内存池。本池建立时需要给出池大小`size`(单位字节),一旦创建完毕后则后续无法再扩大。


返回值:成功则返回内存池结构指针,否则返回`NULL`


mln\_alloc\_destroy



void mln_alloc_destroy(mln_alloc_t *pool);


描述:销毁内存池。销毁操作会将内存池中管理的所有内存进行统一释放。


返回值:无


mln\_alloc\_m



void *mln_alloc_m(mln_alloc_t *pool, mln_size_t size);


描述:从内存池`pool`中分配一个`size`大小的内存。如果内存池是共享内存内存池,则会从共享内存中进行分配,否则从堆内存中进行分配。


返回值:成功则返回内存起始地址,否则返回`NULL`


mln\_alloc\_c



void *mln_alloc_c(mln_alloc_t *pool, mln_size_t size);


描述:从内存池`pool`中分配一个`size`大小的内存,且该内存会被清零。


返回值:成功则返回内存起始地址,否则返回`NULL`


mln\_alloc\_re



void *mln_alloc_re(mln_alloc_t *pool, void *ptr, mln_size_t size);


描述:从内存池`pool`中分配一个`size`大小的内存,并将`ptr`指向的内存中的数据拷贝到新的内存中。


`ptr`必须为内存池分配的内存起始地址。若`size`为`0`,`ptr`指向的内存会被释放。


返回值:成功则返回内存起始地址,否则返回`NULL`


mln\_alloc\_free



void mln_alloc_free(void *ptr);


描述:释放`ptr`指向的内存。**注意**:`ptr`必须为分配函数返回的地址,而不可以是分配的内存中某一个位置。


返回值:无


mln\_alloc\_shm\_rdlock



int mln_alloc_shm_rdlock(mln_alloc_t *pool);


描述:读锁定。本函数会等待直到锁资源可用,并将之锁定。


本函数及后续锁相关函数均用于共享内存内存池。


出于对读多写少的场景考虑,给共享内存配备的是读写锁,而非互斥锁。


返回值:成功返回`0`,否则返回`非0`


mln\_alloc\_shm\_tryrdlock



int mln_alloc_shm_tryrdlock(mln_alloc_t *pool);


描述:尝试读锁定。本函数不会挂起等待锁资源可用。


返回值:成功返回`0`,否则返回`非0`


mln\_alloc\_shm\_wrlock



int mln_alloc_shm_wrlock(mln_alloc_t *pool);


描述:写锁定。本函数会等待直到锁资源可用,并将之锁定。


返回值:成功返回`0`,否则返回`非0`


mln\_alloc\_shm\_trywrlock



int mln_alloc_shm_trywrlock(mln_alloc_t *pool);


描述:尝试写锁定。本函数不会挂起等待锁资源可用。


返回值:成功返回`0`,否则返回`非0`


mln\_alloc\_shm\_unlock



int mln_alloc_shm_unlock(mln_alloc_t *pool);


描述:解除锁定。


返回值:成功返回`0`,否则返回`非0`


示例



#include <stdio.h>
#include <stdlib.h>
#include “mln_core.h”
#include “mln_log.h”
#include “mln_alloc.h”

int main(int argc, char *argv[])
{
char *p;
mln_alloc_t *pool;
struct mln_core_attr cattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = NULL;
if (mln\_core\_init(&cattr) < 0) {
    fprintf(stderr, "init failed\n");
    return -1;
}

pool = mln\_alloc\_init();
if (pool == NULL) {
    mln\_log(error, "pool init failed\n");
    return -1;
}

p = (char \*)mln\_alloc\_m(pool, 6);
if (p == NULL) {
    mln\_log(error, "alloc failed\n");
    return -1;
}

memcpy(p, "hello", 5);
p[5] = 0;
mln\_log(debug, "%s\n", p);

mln\_alloc\_free(p);

return 0;

}


### 线程池


在Melon中支持两种多线程模式,线程池是其中一种,另一种请参见后续的多线程框架文章。


**注意**:在每个进程中仅允许存在一个线程池。


#### 头文件



#include “mln_thread_pool.h”


#### 函数


##### mln\_thread\_pool\_run



int mln_thread_pool_run(struct mln_thread_pool_attr *tpattr);

struct mln_thread_pool_attr {
void *main_data;
mln_thread_process child_process_handler;
mln_thread_process main_process_handler;
mln_thread_dataFree free_handler;
mln_u64_t cond_timeout; /*ms*/
mln_u32_t max;
mln_u32_t concurrency;
};
typedef int (*mln_thread_process)(void *);
typedef void (*mln_thread_dataFree)(void *);


描述:创建并运行内存池。


线程池由主线程进行管理和做一部分处理后下发任务,子线程组则接受任务进行处理。


初始状态下,是不存在子线程的,当有任务需要下发时会自动创建子线程。当任务处理完后,子线程会延迟释放,避免频繁分配释放资源。


其中参数结构体的每个成员含义如下:


* `main_data` 为主线程的用户自定义数据。
* `child_process_handler` 每个子线程的处理函数,该函数有一个参数为主线程下发任务时给出的数据结构指针,返回值为`0`表示处理正常,`非0`表示处理异常,异常时会有日志输出。
* `main_process_handler` 主线程的处理函数,该函数有一个参数为`main_data`,返回值为`0`表示处理正常,`非0`表示处理异常,异常时会有日志输出。**一般情况下,主线程处理函数不应随意自行返回,一旦返回代表线程池处理结束,线程池会被销毁**。
* `free_handler` 为资源释放函数。其资源为主线程下发给子线程的数据结构指针所指向的内容。
* `cond_timeout`为闲置子线程回收定时器,单位为毫秒。当子线程无任务处理,且等待时间超过该定时器时长后,会自行退出。
* `max`线程池允许的最大子线程数量。
* `concurrency`用于`pthread_setconcurrency`设置并行级别参考值,但部分系统并为实现该功能,因此不应该过多依赖该值。在Linux下,该值设为零表示交由本系统实现自行确定并行度。


返回值:本函数返回值与主线程处理函数的返回值保持一致


##### mln\_thread\_pool\_addResource



int mln_thread_pool_addResource(void *data);


描述:将资源`data`放入到资源池中。本函数仅应由主线程调用,用于主线程向子线程下发任务所用。


返回值:成功则返回`0`,否则返回`非0`


##### mln\_thread\_quit



void mln_thread_quit(void);


描述:本函数用于告知线程池,关闭并销毁线程池。


返回值:无


##### mln\_thread\_ResourceInfo



void mln_thread_ResourceInfo(struct mln_thread_pool_info *info);

struct mln_thread_pool_info {
mln_u32_t max_num;
mln_u32_t idle_num;
mln_u32_t cur_num;
mln_size_t res_num;
};


描述:获取当前线程池信息。信息会写入参数结构体中,结构体每个参数含义如下:


* `max_num`:线程池最大子线程数量
* `idle_num`:当前闲置子线程数量
* `cur_num`:当前子线程数量(包含闲置和工作中的子线程)
* `res_num`:当前尚未被处理的资源数量


返回值:无


#### 示例



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include “mln_core.h”
#include “mln_thread_pool.h”
#include “mln_log.h”

static int main_process_handler(void *data);
static int child_process_handler(void *data);
static void free_handler(void *data);

int main(int argc, char *argv[])
{
struct mln_core_attr cattr;
struct mln_thread_pool_attr tpattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = NULL;
if (mln\_core\_init(&cattr) < 0) {
    return -1;
}

tpattr.dataForMain = NULL;
tpattr.child_process_handler = child_process_handler;
tpattr.main_process_handler = main_process_handler;
tpattr.free_handler = free_handler;
tpattr.condTimeout = 10;
tpattr.max = 10;
tpattr.concurrency = 10;
return mln\_thread\_pool\_run(&tpattr);

}

static int child_process_handler(void *data)
{
mln_log(none, “%s\n”, (char *)data);
return 0;
}

static int main_process_handler(void *data)
{
int n;
char *text;

while (1) {
    if ((text = (char \*)malloc(16)) == NULL) {
        return -1;
    }
    n = snprintf(text, 15, "hello world");
    text[n] = 0;
    mln\_thread\_pool\_addResource(text);
    usleep(1000);
}

}

static void free_handler(void *data)
{
free(data);
}


### JSON


#### 头文件



#include “mln_json.h”


#### 函数/宏


##### mln\_json\_new



mln_json_t *mln_json_new(void);


描述:新建json节点,用于生成json字符串之用。


返回值:成功则返回`mln_json_t`指针,否则返回`NULL`


##### mln\_json\_parse



mln_json_t *mln_json_parse(mln_string_t *jstr);


描述:将JSON字符串`jstr`解析成数据结构。


返回值:成功则返回`mln_json_t`指针,否则返回`NULL`


##### mln\_json\_free



void mln_json_free(void *json);


描述:释放`mln_json_t`类型的`json`节点内存。


返回值:无


##### mln\_json\_dump



void mln_json_dump(mln_json_t *j, int n_space, char *prefix);


描述:将json节点`j`的详细信息输出到标准输出。`n_space`表示当前缩进空格数,`prefix`为输出内容的前缀。


返回值:无


##### mln\_json\_generate



mln_string_t *mln_json_generate(mln_json_t *j);


描述:由`mln_json_t`节点结构生成JSON字符串。


返回值:成功返回`mln_string_t`字符串指针,否则返回`NULL`


##### mln\_json\_search\_value



mln_json_t *mln_json_search_value(mln_json_t *j, mln_string_t *key);


描述:从节点`j`中搜索key为`key`的value内容。此时,`j`必须为对象类型(有key: value对的字典)。


返回值:成功则返回`mln_json_t`类型的value,否则返回`NULL`


##### mln\_json\_search\_element



mln_json_t *mln_json_search_element(mln_json_t *j, mln_uauto_t index);


描述:从节点`j`中搜索下标为`index`的元素内容。此时,`j`必须为数组类型。


返回值:成功则返回`mln_json_t`类型的元素节点,否则返回`NULL`


##### mln\_json\_get\_array\_length



mln_uauto_t mln_json_get_array_length(mln_json_t *j);


描述:获取数组的长度。此时`j`必须为数组类型。


返回值:数组长度


##### mln\_json\_update\_obj



int mln_json_update_obj(mln_json_t *j, mln_json_t *key, mln_json_t *val);


描述:将`key`与`val`对添加到`j` JSON节点中。此时,`j`需为对象类型。若`key`已经存在,则将原本value替换为`val`。


返回值:成功则返回`0`,否则返回`-1`


##### mln\_json\_add\_element



int mln_json_add_element(mln_json_t *j, mln_json_t *value);


描述:将`value`加入到数组类型的JSON结构`j`中。


返回值:成功则返回`0`,否则返回`-1`


##### mln\_json\_update\_element



int mln_json_update_element(mln_json_t *j, mln_json_t *value, mln_uauto_t index);


描述:将`value`更新到数组类型JSON结构`j`的下标为`index`的位置上。


返回值:成功则返回`0`,否则返回`-1`


##### mln\_json\_reset



void mln_json_reset(mln_json_t *j);


描述:重置JSON节点`j`数据结构,将其内存进行释放。


返回值:无


##### mln\_json\_remove\_object



mln_json_t *mln_json_remove_object(mln_json_t *j, mln_string_t *key);


描述:将key值为`key`的键值对从对象类型的JSON结构`j`中删除,并将相应value返回。


返回值:存在则返回对应value部分的JSON节点,否则返回`NULL`


##### mln\_json\_remove\_element



mln_json_t *mln_json_remove_element(mln_json_t *j, mln_uauto_t index);


描述:将下标为`index`的元素从数组类型JSON节点上删除并返回。


返回值:存在则返回元素指针,否则返回`NULL`


##### is\_type



M_JSON_IS_OBJECT(json)
M_JSON_IS_ARRAY(json)
M_JSON_IS_STRING(json)
M_JSON_IS_NUMBER(json)
M_JSON_IS_TRUE(json)
M_JSON_IS_FALSE(json)
M_JSON_IS_NULL(json)
M_JSON_IS_NONE(json)


描述:判断`mln_json_t`结构的`json`类型,依次分别为:对象、数组、字符串、数字、布尔真、布尔假、NULL、无类型。


返回值:满足条件返回`非0`,否则返回`0`


##### set\_type



M_JSON_SET_TYPE_NONE(json)
M_JSON_SET_TYPE_OBJECT(json)
M_JSON_SET_TYPE_ARRAY(json)
M_JSON_SET_TYPE_STRING(json)
M_JSON_SET_TYPE_NUMBER(json)
M_JSON_SET_TYPE_TRUE(json)
M_JSON_SET_TYPE_FALSE(json)
M_JSON_SET_TYPE_NULL(json)


描述:给`mln_json_t`类型的`json`节点设置类型,依次分别为:无类型、对象、数组、字符串、数字、布尔真、布尔假、NULL。


返回值:无


##### get\_data



M_JSON_GET_DATA_OBJECT(json)
M_JSON_GET_DATA_ARRAY(json)
M_JSON_GET_DATA_STRING(json)
M_JSON_GET_DATA_NUMBER(json)
M_JSON_GET_DATA_TRUE(json)
M_JSON_GET_DATA_FALSE(json)
M_JSON_GET_DATA_NULL(json)


描述:获取`mln_json_t`类型的`json`节点中对应类型的数据部分。类型依次为:对象、数组、字符串、数字、布尔真、布尔假、NULL。


返回值:


* 对象类型为`mln_hash_t`类型指针
* 数组类型为`mln_rbtree_t`类型指针
* 字符串类型为`mln_string_t`类型指针
* 数字类型为`double`类型值
* 布尔真为`mln_u8_t`类型值
* 布尔假为`mln_u8_t`类型值
* NULL类型为`mln_u8ptr_t`类型的NULL值


##### set\_data



M_JSON_SET_DATA_STRING(json,str)
M_JSON_SET_DATA_NUMBER(json,num)
M_JSON_SET_DATA_TRUE(json)
M_JSON_SET_DATA_FALSE(json)
M_JSON_SET_DATA_NULL(json)


描述:给不同类型的JSON节点`json`设置数据值。对象和数组类型分别使用哈希表和红黑树函数进行操作,其余类型用上述宏进行设置。


**注意**:这里设置的字符串必须是从内存池或堆中分配的内存,栈中内存会出现段错误,因为赋值时不会在宏内自动复制一份而是直接使用。


返回值:无


##### M\_JSON\_SET\_INDEX



M_JSON_SET_INDEX(json,i)


描述:设置`mln_json_t`类型节点`json`的下标为`index`。该宏用于生成JSON字符串中数组的部分。


返回值:无


#### 示例



#include <stdio.h>
#include <stdlib.h>
#include “mln_core.h”
#include “mln_log.h”
#include “mln_string.h”
#include “mln_json.h”

int main(int argc, char *argv[])
{
mln_json_t *j = NULL, *key = NULL, *val = NULL;
mln_string_t s1 = mln_string(“name”);
mln_string_t s2 = mln_string(“Tom”);
mln_string_t *res;
struct mln_core_attr cattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = NULL;
if (mln\_core\_init(&cattr) < 0) {
    fprintf(stderr, "init failed\n");
    return -1;
}

key = mln\_json\_new();
if (key == NULL) {
    mln\_log(error, "init key failed\n");
    goto err;
}
M\_JSON\_SET\_TYPE\_STRING(key);
M\_JSON\_SET\_DATA\_STRING(key, mln\_string\_dup(&s1));//注意,一定是要自行分配内存,不可直接使用栈中内存

val = mln\_json\_new();
if (val == NULL) {
    mln\_log(error, "init val failed\n");
    goto err;
}
M\_JSON\_SET\_TYPE\_STRING(val);
M\_JSON\_SET\_DATA\_STRING(val, mln\_string\_dup(&s2));//注意,一定是要自行分配内存,不可直接使用栈中内存

j = mln\_json\_new();
if (j == NULL) {
    mln\_log(error, "init object failed\n");
    goto err;
}
if (mln\_json\_update\_obj(j, key, val) < 0) {
    mln\_log(error, "update object failed\n");
    goto err;
}
key = val = NULL;

res = mln\_json\_generate(j);
mln\_json\_free(j);
if (res == NULL) {
    mln\_log(error, "generate failed\n");
    goto err;
}
mln\_log(debug, "%S\n", res);

j = mln\_json\_parse(res);
mln\_string\_free(res);
mln\_json\_dump(j, 0, NULL);

mln\_json\_free(j);

return 0;

err:
if (j != NULL) mln_json_free(j);
if (key != NULL) mln_json_free(key);
if (val != NULL) mln_json_free(val);
return -1;
}


### HTTP


#### 头文件



#include “mln_http.h”


#### 函数/宏


##### mln\_http\_init



mln_http_t *mln_http_init(mln_tcp_conn_t *connection, void *data, mln_http_handler body_handler);

typedef int (*mln_http_handler)(mln_http_t *, mln_chain_t **, mln_chain_t **);


描述:创建并初始化`mln_http_t`结构。`connection`是TCP结构,内含TCP套接字。`data`为体处理函数的用户自定义数据部分,用于辅助请求或响应体的处理。`body_handler`是体处理函数,该函数会在每次调用`mln_http_parse`或`mln_http_generate`函数时被调用。体处理函数有三个参数,分别为:http结构,用于解析或生成HTTP报文的双向链表的头和尾节点。


返回值:成功则返回`mln_http_t`结构指针,否则返回`NULL`


##### mln\_http\_destroy



void mln_http_destroy(mln_http_t *http);


描述:销毁`http`结构并释放资源。


返回值:无


##### mln\_http\_reset



void mln_http_reset(mln_http_t *http);


描述:重置`http`结构,但不会将结构释放,可用于下一次处理。


返回值:无


##### mln\_http\_parse



int mln_http_parse(mln_http_t *http, mln_chain_t **in);


描述:用于解析HTTP报文,并将解析的结果写入`http`中。


返回值:


* `M_HTTP_RET_DONE` 解析完成
* `M_HTTP_RET_OK` 解析未完成但未出错,继续传入新的数据使解析完成
* `M_HTTP_RET_ERROR` 解析失败


##### mln\_http\_generate



int mln_http_generate(mln_http_t *http, mln_chain_t **out_head, mln_chain_t **out_tail);


描述:将`http`中HTTP相关信息生成HTTP报文。报文可能不会一次性生成完全,因此可以多次调用。已生成的报文将会存放在`out_head`和`out_tail`指定的双向链表中。


返回值:


* `M_HTTP_RET_DONE` 生成完成
* `M_HTTP_RET_OK` 生成未完成但未出错
* `M_HTTP_RET_ERROR` 生成失败


##### mln\_http\_set\_field



int mln_http_set_field(mln_http_t *http, mln_string_t *key, mln_string_t *val);


描述:设置HTTP头字段。若头字段`key`存在,则会将`val`替换原有值。


返回值:


* `M_HTTP_RET_OK` 处理成功
* `M_HTTP_RET_ERROR`处理失败


##### mln\_http\_get\_field



mln_string_t *mln_http_get_field(mln_http_t *http, mln_string_t *key);


描述:获取HTTP头字段中键为`key`的值。


返回值:成功则返回值字符串结构指针,否则返回`NULL`


##### mln\_http\_field\_iterator



mln_string_t *mln_http_field_iterator(mln_http_t *http, mln_string_t *key);


描述:每次返回一个键为`key`的头字段值(即假设存在多个相同键名的头字段)。


返回值:成功则返回值字符串结构指针,否则返回`NULL`


##### mln\_http\_drop\_field



void mln_http_drop_field(mln_http_t *http, mln_string_t *key);


描述:移除头字段`key`及其值。


返回值:无


##### mln\_http\_dump



void mln_http_dump(mln_http_t *http);


描述:将HTTP信息输出到标准输出,用于调试之用。


返回值:无


##### mln\_http\_get\_connection



mln_http_get_connection(h)


描述:获取类型为`mln_http_t`的`h`中TCP链接结构。


返回值:`mln_tcp_conn_t`类型指针


##### mln\_http\_set\_connection



mln_http_set_connection(h,c)


描述:将`mln_http_t`类型的`h`中TCP链接结构设置为`mln_tcp_conn_t`类型的`c`。


返回值:无


##### mln\_http\_get\_pool



mln_http_get_pool(h)


描述:获取类型为`mln_http_t`的`h`中内存池结构。


返回值:`mln_alloc_t`类型指针


##### mln\_http\_set\_pool



mln_http_set_pool(h,p)


描述:将`mln_http_t`类型的`h`中内存池设置为`mln_alloc_t`类型的`p`。


返回值:无


##### mln\_http\_get\_data



mln_http_get_data(h)


描述:获取类型为`mln_http_t`的`h`中辅助体处理函数的用户自定义数据。


返回值:用户自定义数据指针


##### mln\_http\_set\_data



mln_http_set_data(h,d)


描述:将`mln_http_t`类型的`h`中辅助体处理函数的用户自定义数据设置为`d`。


返回值:无


##### mln\_http\_get\_uri



mln_http_get_uri(h)


描述:获取类型为`mln_http_t`的`h`中URI字符串。


返回值:`mln_string_t`类型指针


##### mln\_http\_set\_uri



mln_http_set_uri(h,u)


描述:将`mln_http_t`类型的`h`中URI设置为`mln_string_t`类型指针的`u`。


返回值:无


##### mln\_http\_get\_args



mln_http_get_args(h)


描述:获取类型为`mln_http_t`的`h`中参数字符串。


返回值:`mln_string_t`类型指针


##### mln\_http\_set\_args



mln_http_set_args(h,a)


描述:将`mln_http_t`类型的`h`中参数设置为`mln_string_t`类型指针的`a`。


返回值:无


##### mln\_http\_get\_status



mln_http_get_status(h)


描述:获取类型为`mln_http_t`的`h`中响应状态字,例如200 400等。


返回值:整型状态字


##### mln\_http\_set\_status



mln_http_set_status(h,s)


描述:将`mln_http_t`类型的`h`中响应状态字设置为整型的`s`。


返回值:无


##### mln\_http\_get\_method



mln_http_get_method(h)


描述:获取类型为`mln_http_t`的`h`中方法字段


返回值:


* `M_HTTP_GET`
* `M_HTTP_POST`
* `M_HTTP_HEAD`
* `M_HTTP_PUT`
* `M_HTTP_DELETE`
* `M_HTTP_TRACE`
* `M_HTTP_CONNECT`
* `M_HTTP_OPTIONS`


##### mln\_http\_set\_method



mln_http_set_method(h,m)


描述:将`mln_http_t`类型的`h`中请求方法设置为`m`,`m`的可用值参考`mln_http_get_method`的返回值部分。


返回值:无


##### mln\_http\_get\_version



mln_http_get_version(h)


描述:获取类型为`mln_http_t`的`h`中HTTP版本


返回值:


* `M_HTTP_VERSION_1_0` HTTP 1.0
* `M_HTTP_VERSION_1_1` HTTP 1.1


##### mln\_http\_set\_version



mln_http_set_version(h,v)


描述:将`mln_http_t`类型的`h`中的HTTP版本号为`v`,`v`的取值参考`mln_http_get_version`的返回值。


返回值:无


##### mln\_http\_get\_type



mln_http_get_type(h)


描述:获取类型为`mln_http_t`的`h`中HTTP类型,即请求还是响应。


返回值:


* `M_HTTP_UNKNOWN`未知类型
* `M_HTTP_REQUEST`请求
* `M_HTTP_RESPONSE`响应


##### mln\_http\_set\_type



mln_http_set_type(h,t)


描述:将`mln_http_t`类型的`h`中报文类型设置为`t`,`t`的取值参考`mln_http_get_type`的返回值。


返回值:无


##### mln\_http\_get\_handler



mln_http_get_handler(h)


描述:获取类型为`mln_http_t`的`h`中体处理函数指针。


返回值:类型为`mln_http_handler`的函数指针


##### mln\_http\_set\_handler



mln_http_set_handler(h,hlr)


描述:将`mln_http_t`类型的`h`中提处理函数设置为`mln_http_handler`类型的`hlr`。


返回值:无


##### mln\_http\_get\_response\_msg



mln_http_get_response_msg(h)


描述:获取类型为`mln_http_t`的`h`中响应信息,即类似:Bad Request 或 Internal Server Error等字符串。


返回值:`mln_string_t`类型指针


##### mln\_http\_set\_response\_msg



mln_http_set_response_msg(h,m)


描述:将`mln_http_t`类型的`h`中响应信息设置为`mln_string_t`类型指针的`m`。


返回值:无


##### mln\_http\_get\_error



mln_http_get_error(h)

#define M_HTTP_CONTINUE 100
#define M_HTTP_SWITCHING_PROTOCOLS 101
#define M_HTTP_PROCESSING 102
#define M_HTTP_OK 200
#define M_HTTP_CREATED 201
#define M_HTTP_ACCEPTED 202
#define M_HTTP_NON_AUTHORITATIVE_INFORMATION 203
#define M_HTTP_NO_CONTENT 204
#define M_HTTP_RESET_CONTENT 205
#define M_HTTP_PARTIAL_CONTENT 206
#define M_HTTP_MULTI_STATUS 207
#define M_HTTP_MULTIPLE_CHOICES 300
#define M_HTTP_MOVED_PERMANENTLY 301
#define M_HTTP_MOVED_TEMPORARILY 302
#define M_HTTP_SEE_OTHER 303
#define M_HTTP_NOT_MODIFIED 304
#define M_HTTP_USE_PROXY 305
#define M_HTTP_SWITCH_PROXY 306
#define M_HTTP_TEMPORARY_REDIRECT 307
#define M_HTTP_BAD_REQUEST 400
#define M_HTTP_UNAUTHORIZED 401
#define M_HTTP_PAYMENT_REQUIRED 402
#define M_HTTP_FORBIDDEN 403
#define M_HTTP_NOT_FOUND 404
#define M_HTTP_METHOD_NOT_ALLOWED 405
#define M_HTTP_NOT_ACCEPTABLE 406
#define M_HTTP_PROXY_AUTHENTICATION_REQUIRED 407
#define M_HTTP_REQUEST_TIMEOUT 408
#define M_HTTP_CONFLICT 409
#define M_HTTP_GONE 410
#define M_HTTP_LENGTH_REQUIRED 411
#define M_HTTP_PRECONDITION_FAILED 412
#define M_HTTP_REQUEST_ENTITY_TOO_LARGE 413
#define M_HTTP_REQUEST_URI_TOO_LARGE 414
#define M_HTTP_UNSUPPORTED_MEDIA_TYPE 415
#define M_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416
#define M_HTTP_EXPECTATION_FAILED 417
#define M_HTTP_TOO_MANY_CONNECTIONS 421
#define M_HTTP_UNPROCESSABLE_ENTITY 422
#define M_HTTP_LOCKED 423
#define M_HTTP_FAILED_DEPENDENCY 424
#define M_HTTP_UNORDERED_COLLECTION 425
#define M_HTTP_UPGRADE_REQUIRED 426
#define M_HTTP_RETRY_WITH 449
#define M_HTTP_INTERNAL_SERVER_ERROR 500
#define M_HTTP_NOT_IMPLEMENTED 501
#define M_HTTP_BAD_GATEWAY 502
#define M_HTTP_SERVICE_UNAVAILABLE 503
#define M_HTTP_GATEWAY_TIMEOUT 504
#define M_HTTP_VERSION_NOT_SUPPORTED 505
#define M_HTTP_VARIANT_ALSO_NEGOTIATES 506
#define M_HTTP_INSUFFICIENT_STORAGE 507
#define M_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509
#define M_HTTP_NOT_EXTENDED 510
#define M_HTTP_UNPARSEABLE_RESPONSE_HEADERS 600


描述:获取类型为`mln_http_t`的`h`中错误信息。


返回值:宏定义的错误值


##### mln\_http\_set\_error



mln_http_set_error(h,e)


描述:将`mln_http_t`类型的`h`中错误信息设置为`e`,`e`的取值参见`mln_http_get_error`中的宏定义。


返回值:无


##### mln\_http\_get\_header



mln_http_get_header(h)


描述:获取类型为`mln_http_t`的`h`中头字段结构。


返回值:`mln_hash_t`类型结构


#### 示例



#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include “mln_core.h”
#include “mln_log.h”
#include “mln_http.h”
#include “mln_file.h”

static void mln_accept(mln_event_t *ev, int fd, void *data);
static int mln_http_recv_body_handler(mln_http_t *http, mln_chain_t **in, mln_chain_t **nil);
static void mln_recv(mln_event_t *ev, int fd, void *data);
static void mln_quit(mln_event_t *ev, int fd, void *data);
static void mln_send(mln_event_t *ev, int fd, void *data);
static int mln_http_send_body_handler(mln_http_t *http, mln_chain_t **body_head, mln_chain_t **body_tail);

static void worker_process(mln_event_t *ev)
{
mln_u16_t port = 1234;
mln_s8_t ip[] = “0.0.0.0”;
struct sockaddr_in addr;
int val = 1;
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0) {
mln_log(error, “listen socket error\n”);
return;
}
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
mln_log(error, “setsockopt error\n”);
close(listenfd);
return;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
mln_log(error, “bind error\n”);
close(listenfd);
return;
}
if (listen(listenfd, 511) < 0) {
mln_log(error, “listen error\n”);
close(listenfd);
return;
}

if (mln\_event\_set\_fd(ev, \
                     listenfd, \
                     M_EV_RECV|M_EV_NONBLOCK, \
                     M_EV_UNLIMITED, \
                     NULL, \
                     mln_accept) < 0)
{
    mln\_log(error, "listen sock set event error\n");
    close(listenfd);
    return;
}

}

static void mln_accept(mln_event_t *ev, int fd, void *data)
{
mln_tcp_conn_t *connection;
mln_http_t *http;
int connfd;
socklen_t len;
struct sockaddr_in addr;

while (1) {
    memset(&addr, 0, sizeof(addr));
    len = sizeof(addr);
    connfd = accept(fd, (struct sockaddr \*)&addr, &len);
    if (connfd < 0) {
        if (errno == EAGAIN) break;
        if (errno == EINTR) continue;
        perror("accept");
        exit(1);
    }

    connection = (mln_tcp_conn_t \*)malloc(sizeof(mln_tcp_conn_t));
    if (connection == NULL) {
        fprintf(stderr, "3No memory.\n");
        close(connfd);
        continue;
    }
    if (mln\_tcp\_conn\_init(connection, connfd) < 0) {
        fprintf(stderr, "4No memory.\n");
        close(connfd);
        free(connection);
        continue;
    }

    http = mln\_http\_init(connection, NULL, mln_http_recv_body_handler);
    if (http == NULL) {
        fprintf(stderr, "5No memory.\n");
        mln\_tcp\_conn\_destroy(connection);
        free(connection);
        close(connfd);
        continue;
    }

    if (mln\_event\_set\_fd(ev, \
                         connfd, \
                         M_EV_RECV|M_EV_NONBLOCK, \
                         M_EV_UNLIMITED, \
                         http, \
                         mln_recv) < 0)
    {
        fprintf(stderr, "6No memory.\n");
        mln\_http\_destroy(http);
        mln\_tcp\_conn\_destroy(connection);
        free(connection);
        close(connfd);
        continue;
    }
}

}

static void mln_quit(mln_event_t *ev, int fd, void *data)
{
mln_http_t *http = (mln_http_t *)data;
mln_tcp_conn_t *connection = mln_http_get_connection(http);

mln\_event\_set\_fd(ev, fd, M_EV_CLR, M_EV_UNLIMITED, NULL, NULL);
mln\_http\_destroy(http);
mln\_tcp\_conn\_destroy(connection);
free(connection);
close(fd);

}

static void mln_recv(mln_event_t *ev, int fd, void *data)
{
mln_http_t *http = (mln_http_t *)data;
mln_tcp_conn_t *connection = mln_http_get_connection(http);
int ret, rc;
mln_chain_t *c;

while (1) {
    ret = mln\_tcp\_conn\_recv(connection, M_C_TYPE_MEMORY);
    if (ret == M_C_FINISH) {
        continue;
    } else if (ret == M_C_NOTYET) {
        c = mln\_tcp\_conn\_remove(connection, M_C_RECV);
        if (c != NULL) {
            rc = mln\_http\_parse(http, &c);
            if (c != NULL) {
                mln\_tcp\_conn\_append\_chain(connection, c, NULL, M_C_RECV);
            }
            if (rc == M_HTTP_RET_OK) {
                return;
            } else if (rc == M_HTTP_RET_DONE) {
                mln\_send(ev, fd, data);
            } else {
                fprintf(stderr, "Http parse error. error\_code:%u\n", mln\_http\_get\_error(http));
                mln\_quit(ev, fd, data);
                return;
            }
        }
        break;
    } else if (ret == M_C_CLOSED) {
        c = mln\_tcp\_conn\_remove(connection, M_C_RECV);
        if (c != NULL) {
            rc = mln\_http\_parse(http, &c);
            if (c != NULL) {
                mln\_tcp\_conn\_append\_chain(connection, c, NULL, M_C_RECV);
            }
            if (rc == M_HTTP_RET_ERROR) {
                fprintf(stderr, "Http parse error. error\_code:%u\n", mln\_http\_get\_error(http));
            }
        }
        mln\_quit(ev, fd, data);
        return;
    } else if (ret == M_C_ERROR) {
        mln\_quit(ev, fd, data);
        return;
    }
}

}

static int mln_http_recv_body_handler(mln_http_t *http, mln_chain_t **in, mln_chain_t **nil)
{
mln_u32_t method = mln_http_get_method(http);
if (method == M_HTTP_GET)
return M_HTTP_RET_DONE;
mln_http_set_error(http, M_HTTP_NOT_IMPLEMENTED);
return M_HTTP_RET_ERROR;
}

static void mln_send(mln_event_t *ev, int fd, void *data)
{
mln_http_t *http = (mln_http_t *)data;
mln_tcp_conn_t *connection = mln_http_get_connection(http);
mln_chain_t *c = mln_tcp_conn_get_head(connection, M_C_SEND);
int ret;

if (c == NULL) {
    mln\_http\_reset(http);
    mln\_http\_set\_status(http, M_HTTP_OK);
    mln\_http\_set\_version(http, M_HTTP_VERSION_1_0);
    mln\_http\_set\_type(http, M_HTTP_RESPONSE);
    mln\_http\_set\_handler(http, mln_http_send_body_handler);
    mln_chain_t \*body_head = NULL, \*body_tail = NULL;
    if (mln\_http\_generate(http, &body_head, &body_tail) == M_HTTP_RET_ERROR) {
        fprintf(stderr, "mln\_http\_generate() failed. %u\n", mln\_http\_get\_error(http));
        mln\_quit(ev, fd, data);
        return;
    }
    mln\_tcp\_conn\_append\_chain(connection, body_head, body_tail, M_C_SEND);
}

while ((c = mln\_tcp\_conn\_get\_head(connection, M_C_SEND)) != NULL) {
    ret = mln\_tcp\_conn\_send(connection);
    if (ret == M_C_FINISH) {
        mln\_quit(ev, fd, data);
        break;
    } else if (ret == M_C_NOTYET) {
        mln\_chain\_pool\_release\_all(mln\_tcp\_conn\_remove(connection, M_C_SENT));
        mln\_event\_set\_fd(ev, fd, M_EV_SEND|M_EV_APPEND|M_EV_NONBLOCK, M_EV_UNLIMITED, data, mln_send);
        return;
    } else if (ret == M_C_ERROR) {
        mln\_quit(ev, fd, data);
        return;
    } else {
        fprintf(stderr, "Shouldn't be here.\n");
        abort();
    }
}

}

static int mln_http_send_body_handler(mln_http_t *http, mln_chain_t **body_head, mln_chain_t **body_tail)
{
mln_u8ptr_t buf;
mln_alloc_t *pool = mln_http_get_pool(http);
mln_string_t cttype_key = mln_string(“Content-Type”);
mln_string_t cttype_val = mln_string(“text/html”);

buf = mln\_alloc\_m(pool, 5);
if (buf == NULL) {
    mln\_http\_set\_error(http, M_HTTP_INTERNAL_SERVER_ERROR);
    return M_HTTP_RET_ERROR;
}
memcpy(buf, "hello", 5);

if (mln\_http\_set\_field(http, &cttype_key, &cttype_val) == M_HTTP_RET_ERROR) {
    mln\_http\_set\_error(http, M_HTTP_INTERNAL_SERVER_ERROR);
    return M_HTTP_RET_ERROR;
}

mln_string_t ctlen_key = mln\_string("Content-Length");
mln_string_t ctlen_val = mln\_string("5");
if (mln\_http\_set\_field(http, &ctlen_key, &ctlen_val) == M_HTTP_RET_ERROR) {
    mln\_http\_set\_error(http, M_HTTP_INTERNAL_SERVER_ERROR);
    return M_HTTP_RET_ERROR;
}

mln_chain_t \*c = mln\_chain\_new(pool);
if (c == NULL) {
    mln\_http\_set\_error(http, M_HTTP_INTERNAL_SERVER_ERROR);
    return M_HTTP_RET_ERROR;
}
mln_buf_t \*b = mln\_buf\_new(pool);
if (b == NULL) {
    mln\_chain\_pool\_release(c);
    mln\_http\_set\_error(http, M_HTTP_INTERNAL_SERVER_ERROR);
    return M_HTTP_RET_ERROR;
}
c->buf = b;
b->left_pos = b->pos = b->start = buf;
b->last = b->end = buf + 5;
b->in_memory = 1;
b->last_buf = 1;
b->last_in_chain = 1;

if (\*body_head == NULL) {
    \*body_head = \*body_tail = c;
} else {
    (\*body_tail)->next = c;
    \*body_tail = c;
}

return M_HTTP_RET_DONE;

}

int main(int argc, char *argv[])
{
struct mln_core_attr cattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = worker_process;
return mln\_core\_init(&cattr);

}


### 矩阵运算


#### 头文件



#include “mln_matrix.h”


#### 相关结构



typedef struct {
mln_size_t row;//矩阵的行数
mln_size_t col;//矩阵的列数
double *data;//一个一维数组,包含了矩阵内所有元素,按行一次排列
mln_u32_t is_ref:1;//标识data是否为外部引用,该标记用于释放矩阵结构时忽略对data的释放
} mln_matrix_t;


#### 函数


##### mln\_matrix\_new



mln_matrix_t *mln_matrix_new(mln_size_t row, mln_size_t col, double *data, mln_u32_t is_ref);


描述:创建一个`row`行`col`列,数据为`data`的矩阵。若`is_ref`为`0`则表示矩阵结构会完全复制一个`data`在其中,否则直接引用`data`。


返回值:成功则返回矩阵结构指针,否则返回`NULL`


##### mln\_matrix\_free



void mln_matrix_free(mln_matrix_t *matrix);


描述:释放矩阵结构内存。


返回值:无


##### mln\_matrix\_mul



mln_matrix_t *mln_matrix_mul(mln_matrix_t *m1, mln_matrix_t *m2);


描述:矩阵乘法。


返回值:成功则返回结果矩阵指针,否则返回`NULL`


##### mln\_matrix\_inverse



mln_matrix_t *mln_matrix_inverse(mln_matrix_t *matrix);


描述:矩阵求逆。**注意**:矩阵求逆要求是该矩阵为方阵。


返回值:成功则返回结果矩阵指针,否则返回`NULL`


##### mln\_matrix\_dump



void mln_matrix_dump(mln_matrix_t *matrix);


描述:将矩阵的信息输出到标准输出中。仅用于调试。


返回值:无


#### 示例



#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include “mln_core.h”
#include “mln_log.h”
#include “mln_matrix.h”

int main(int argc, char *argv[])
{
mln_matrix_t *a, *b;
double data[] = {1, 1, 1, 1, 2, 4, 2, 8, 64};
struct mln_core_attr cattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = NULL;
if (mln\_core\_init(&cattr) < 0) {
    fprintf(stderr, "init failed\n");
    return -1;
}

a = mln\_matrix\_new(3, 3, data, 1);
if (a == NULL) {
    mln\_log(error, "init matrix failed\n");
    return -1;
}
mln\_matrix\_dump(a);

b = mln\_matrix\_inverse(a);
mln\_matrix\_free(a);
if (b == NULL) {
    mln\_log(error, "inverse failed: %s\n", strerror(errno));
    return -1;
}
mln\_matrix\_dump(b);
mln\_matrix\_free(b);

return 0;

}


### 大数计算


#### 头文件



#include “mln_bignum.h”


#### 相关结构



typedef struct {
mln_u32_t tag;//正负数标记
mln_u32_t length;//当前大数数值所使用到的data的元素个数
mln_u64_t data[M_BIGNUM_SIZE];//大数数值
} mln_bignum_t;

#define M_BIGNUM_POSITIVE 0 //正数
#define M_BIGNUM_NEGATIVE 1 //负数

#define M_BIGNUM_SIZE 257


Melon中大数的实现是定长的,即大数是有上限的,目前支持到最大2048位。


#### 函数/宏


##### mln\_bignum\_init



mln_bignum_t *mln_bignum_init(void);


描述:创建并初始化大数结构`mln_bignum_t`,该结构由`malloc`分配而来。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_pool\_init



mln_bignum_t *mln_bignum_pool_init(mln_alloc_t *pool);


描述:创建并初始化大数结构`mln_bignum_t`,该结构由`pool`指定的内存池分配而来。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_free



void mln_bignum_free(mln_bignum_t *bn);


描述:释放大数结构`bn`,该结构应由`mln_bignum_init`分配而来。


返回值:无


##### mln\_bignum\_pool\_free



void mln_bignum_pool_free(mln_bignum_t *bn);


描述:释放大数结构`bn`,该结构应由`mln_bignum_pool_init`分配而来。


返回值:无


##### mln\_bignum\_dup



mln_bignum_t *mln_bignum_dup(mln_bignum_t *bn);


描述:完全复制一份大数结构`bn`,复制品由`malloc`分配内存。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_pool\_dup



mln_bignum_t *mln_bignum_pool_dup(mln_alloc_t *pool, mln_bignum_t *bn);


描述:完全复制一份大数结构`bn`,复制品由`pool`指定的内存池上分配内存。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_assign



int mln_bignum_assign(mln_bignum_t *bn, mln_s8ptr_t sval, mln_u32_t len);


描述:将`sval`和`len`表示的字符串形式的大数赋值给大数结构`bn`。




![img](https://img-blog.csdnimg.cn/img_convert/416b996ab569cc5ed50a5c11cea7022e.png)
![img](https://img-blog.csdnimg.cn/img_convert/d4386d9095e27a8e4e84e7561f801bea.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

rix\_dump



void mln_matrix_dump(mln_matrix_t *matrix);


描述:将矩阵的信息输出到标准输出中。仅用于调试。


返回值:无


#### 示例



#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include “mln_core.h”
#include “mln_log.h”
#include “mln_matrix.h”

int main(int argc, char *argv[])
{
mln_matrix_t *a, *b;
double data[] = {1, 1, 1, 1, 2, 4, 2, 8, 64};
struct mln_core_attr cattr;

cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = NULL;
cattr.worker_process = NULL;
if (mln\_core\_init(&cattr) < 0) {
    fprintf(stderr, "init failed\n");
    return -1;
}

a = mln\_matrix\_new(3, 3, data, 1);
if (a == NULL) {
    mln\_log(error, "init matrix failed\n");
    return -1;
}
mln\_matrix\_dump(a);

b = mln\_matrix\_inverse(a);
mln\_matrix\_free(a);
if (b == NULL) {
    mln\_log(error, "inverse failed: %s\n", strerror(errno));
    return -1;
}
mln\_matrix\_dump(b);
mln\_matrix\_free(b);

return 0;

}


### 大数计算


#### 头文件



#include “mln_bignum.h”


#### 相关结构



typedef struct {
mln_u32_t tag;//正负数标记
mln_u32_t length;//当前大数数值所使用到的data的元素个数
mln_u64_t data[M_BIGNUM_SIZE];//大数数值
} mln_bignum_t;

#define M_BIGNUM_POSITIVE 0 //正数
#define M_BIGNUM_NEGATIVE 1 //负数

#define M_BIGNUM_SIZE 257


Melon中大数的实现是定长的,即大数是有上限的,目前支持到最大2048位。


#### 函数/宏


##### mln\_bignum\_init



mln_bignum_t *mln_bignum_init(void);


描述:创建并初始化大数结构`mln_bignum_t`,该结构由`malloc`分配而来。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_pool\_init



mln_bignum_t *mln_bignum_pool_init(mln_alloc_t *pool);


描述:创建并初始化大数结构`mln_bignum_t`,该结构由`pool`指定的内存池分配而来。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_free



void mln_bignum_free(mln_bignum_t *bn);


描述:释放大数结构`bn`,该结构应由`mln_bignum_init`分配而来。


返回值:无


##### mln\_bignum\_pool\_free



void mln_bignum_pool_free(mln_bignum_t *bn);


描述:释放大数结构`bn`,该结构应由`mln_bignum_pool_init`分配而来。


返回值:无


##### mln\_bignum\_dup



mln_bignum_t *mln_bignum_dup(mln_bignum_t *bn);


描述:完全复制一份大数结构`bn`,复制品由`malloc`分配内存。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_pool\_dup



mln_bignum_t *mln_bignum_pool_dup(mln_alloc_t *pool, mln_bignum_t *bn);


描述:完全复制一份大数结构`bn`,复制品由`pool`指定的内存池上分配内存。


返回值:成功则返回大数结构指针,否则返回`NULL`


##### mln\_bignum\_assign



int mln_bignum_assign(mln_bignum_t *bn, mln_s8ptr_t sval, mln_u32_t len);


描述:将`sval`和`len`表示的字符串形式的大数赋值给大数结构`bn`。




[外链图片转存中...(img-ADcOAGDO-1715852367766)]
[外链图片转存中...(img-qRFFhUiR-1715852367766)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值