简述:
Mongoose前身为shttpd,使用标准C/C++编写而成,转为嵌入式设备设计的,支持跨平台的网络服务器库。Mongoose实现了非阻塞式事件驱动API,支持TCP, UDP, HTTP, WebSocket, CoAP, MQTT。
Mongoose的三个基本结构体:
struct mg_mgr; // 持有所有活动的连接的事件管理器struct mg_connection ; // 用于连接的套接字状态的描述struct mbuf ; // 用于接收和发送数据缓存的描述
声明与初始化事件管理器
struct mg_mgr mgr; mg_mgr_init(&mgr, NULL);
创建连接,比如创建一个服务器端的监听套接字
struct mg_connection *c = mg_bind(&mgr, "80", ev_handler_function); mg_set_protocol_http_websocket(c);
轮询处理:遍历所有套接字,接收新的连接请求,发送与接受数据,关闭连接,事件处理等
for (;;) { mg_mgr_poll(&mgr, 1000); }
收发缓冲区
每个连接都有自己的收发缓冲区struct mbuf,当Mongoose 接收到数据时数据被追加到接收缓冲区并触发一个MG_EV_RECV 事件。当需要发送数据时,只需要使用 mg_send()或者mg_printf()将数据追加到发送缓冲区,当数据发送成功,Mongoose 将数据从发送缓冲区删除并发送一个MG_EV_SEND事件。当连接关闭时,触发MG_EV_CLOSE事件。以下为mbuf的定义:
/* Memory buffer descriptor */struct mbuf { char *buf; /* Buffer pointer */ size_t len; /* Data length. Data is located between offset 0 and len. */ size_t size; /* Buffer size allocated by realloc(1). Must be >= len */};
事件及事件处理函数
Mongoose 为连接、读写、关闭等都定义了事件,每个连接都有与其关联的事件处理函数——该函数由用户自身实现,该函数的原型如下:
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { switch (ev) { /* Event handler code that defines behavior of the connection */ ... } }
典型的事件序列如下:
以下为Mongoose的核心事件:
连接标记位
每个连接都有自己的标记位,比如当创建一个UDP连接时,Mongoose 将为这个连接的标记为设置为MG_F_UDP。
以下标记为用户设定:
- MG_F_FINISHED_SENDING_DATA:告诉Mongoose 数据已经全部存放到了发送缓冲区,当Mongoose 将数据发送完毕时,主动关闭连接。
- MG_F_BUFFER_BUT_DONT_SEND :告诉Mongoose 只将数据追加到缓冲区但是不要发送数据,因为数据之后可能会被修改,当MG_F_BUFFER_BUT_DONT_SEND标记位被清除时数据再被发送
- MG_F_CLOSE_IMMEDIATELY :告诉Mongoose 立马关闭连接,一般在出错的时候设置
- MG_F_USER_1, MG_F_USER_2, MG_F_USER_3, MG_F_USER_4:用户自定义,用来存放应用的指定状态
以下标记由Mongoose 设定:
编译选项:
Mongoose 源代码由单一的c文件构成,Mongoose 所支持的协议都由它提供。在编译时Mongoose 可以去除不需要的功能以减小执行文件的大小。比如可以使用-D MG_DISABLE_MQTT -D MG_DISABLE_COAP去除代码中的MQTT和CoAP的支持代码。
linux下的编译样例:
cc my_app.c mongoose.c -D MG_DISABLE_MQTT -D MG_DISABLE_COAP
Mongoose 的使用样例:
1.将mongoose.c 和mongoose.h拷贝到你的工程目录下
2.使用mongoose提供的API编写工程,例如my_app.c
3.编译工程:cc my_app.c mongoose.c
#include "mongoose.h" // Include Mongoose API definitions// Define an event handler functionstatic void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct mbuf *io = &nc->recv_mbuf; switch (ev) { case MG_EV_RECV: // This event handler implements simple TCP echo server mg_send(nc, io->buf, io->len); // Echo received data back mbuf_remove(io, io->len); // Discard data from recv buffer break; default: break; } }int main(void) { struct mg_mgr mgr; mg_mgr_init(&mgr, NULL); // Initialize event manager object // Note that many connections can be added to a single event manager // Connections can be created at any point, e.g. in event handler function mg_bind(&mgr, "1234", ev_handler); // Create listening connection and add it to the event manager for (;;) { // Start infinite event loop mg_mgr_poll(&mgr, 1000); } mg_mgr_free(&mgr); return 0; }