mongoose作为一种轻量级的WEB服务器,适合在嵌入式设备中使用。其源码只有两个文件:moogoose.c、mongoose.h。
因为6.7版本后,多线程需要自己实现,最近抽空自己整理了以下,希望可以帮到需要的人。当然如果发现有bug可以留言反馈,一起完善。
使用mongoose,其中有几个关键的结构体需要了解,有需要可以去深入了解源码,理解这两个关键结构体的各个字段。mg_mgr
: 用于管理连接、事件等的Manager。mg_connection
: 单个连接,保存了连接信息。
首先需要了解下多线程的实现流程,流程是IO线程收到请求后,将请求通过socket发往工作线程,工作线程处理完后,通过mg_broadcast
方法返回IO线程,mongoose内部也有一对socket用于工作线程向IO线程通信,IO线程收到后向对应的连接回写结果。
接下来一步步介绍实现原理:
1.mg_socketpair 创建一对socket
if (mg_socketpair(sock, SOCK_STREAM) == 0) {
perror("Opening socket pair");
exit(1);
}
创建一对socket,用于接受请求的IO线程,将我们需要的数据发送到处理线程。
另外这里有个隐藏的坑。mongoose 的socket 实现 mg_broadcast 利用了其定义的ctl_msg
结构体进行传输,其中MG_CTL_MSG_MESSAGE_SIZE
默认值是8192,因此如果你的返回结果超过8k会有问题,需要将该值调大。其定义如下:
struct ctl_msg {
mg_event_handler_t callback;
char message[MG_CTL_MSG_MESSAGE_SIZE];
};
如果不想用socket从IO线程向工作线程发请求的话,我们也可以使用队列之类的,IO线程将请求往队列扔,工作线程一直从队列读请求。这里就不写具体实现了。
2.使用mg_start_thread创新消息处理线程
高版本的mongoose 的多线程的实现是使用mg_start_thread创建消息处理线程worker_thread_proc。
for (int i = 0; i < s_num_worker_threads; i++) {
mg_start_thread(worker_thread_proc, &mgr);
}
工作线程通过socket接收数据,处理完成后,处理完后调用mg_broadcast
将work_result
返回IO线程,其中on_work_complete
是返回IO线程后需要执行的方法。这里注意,上文描述过mg_broadcast的数据长度默认是8k,如果返回的数据超过这个长度需要提前设置最大长度。
3.IO线程(接收请求)
使用mg_bind绑定IO线程 ev_handler,在MG_EV_ACCEPT
事件时,为