【mongoosec的入门】

前言

Mongoose 基于C的web库,这篇文章记录了Mongoose的基本知识点,在下小白一枚,如有不对的地方请多多指正。

Mongoose是什么?

Mongoose是一个用C语言编写的网络库,可以用于嵌入式网络编程。它为TCP、UDP、HTTP、WebSocket、CoAP、MQTT等协议实现了事件驱动的非阻塞API,用于客户机和服务器模式。
Mongoose有三种基本数据结构:
(1)mg_mgr保存所有活动连接的事件管理器;
(2)mg_connection描述连接;
(3)mbuf描述接收/发送数据的缓冲区;

连接(connections):由结构体mg_connection结构体描述,连接方式包括:listening(由mg_bind()函数创建),outbound(由mg_connect()函数创建),inbound(监听接收的连接);

实现

Mongoose程序是事件驱动应用程序,一般通过以下步骤实现:
(1)构建事件管理器

	struct mg_mgr mgr;  mg_mgr_init(&mgr, NULL);

(2)创建连接(服务器程序的监听连接)

	struct mg_connection *c = mg_bind(&mgr, "80", ev_handler_function);
	mg_set_protocol_http_websocket(c);

(3)创建事件循环

	while(true) {
	mg_mgr_poll(&mgr, 1000);
	}//mg_mgr_poll() 遍历所有socket,接受新连接,发送和接收数据,关闭连接并调用事件处理函数

内存缓存和数据的收发

	每个连接包含一个发送(struct mg_connection::send_mbuf )和一个缓存( struct mg_connection::recv_mbuf)。
	当数据接收后,Mongoose将接收到的数据加到recv_mbuf后面,并触发一个MG_EV_RECV事件。
	用户通过输出函数(如mg_send()  / mg_printf())将数据发送回去,输出函数将数据追加到send_mbuf。
	成功地将数据写到socket后,它将丢弃struct mg_connection::send_mbuf 里的数据,并发送一个MG_EV_SEND事件。
	当连接关闭后,发送一个MG_EV_CLOSE事件。

事件处理函数

每个连接都有一个与之关联的事件处理函数。这些函数必须由用户实现。事件处理器是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 */
    		...
 		 }
	}
struct mg_connection *nc : 接收事件的连接。int ev : 时间编号,定义在mongoose.h。
例如,当数据来自于一个inbound连接,ev就是MG_EV_RECV。
void *ev_data 指针指向event-specific事件,确切描述每个事件的意义(不同的事件有不同的意义,当发生MG_EV_RECV事件,ev_data是int *指针,指向从远程接收并保存到接收IO缓冲区中的字节数)。当发生Protocol-specific事件,ev_data指向保存protocol-specific信息的结构体。

事件

Mongoose接收传入连接、读取和写入数据,并在适当时为每个连接调用指定的事件处理程序。
典型的事件顺序有:
(1)出站连接:MG_EV_CONNECT -> (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL ...) -> MG_EV_CLOSE,
(2)入站连接:MG_EV_ACCEPT -> (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL ...) -> MG_EV_CLOSE

Mongoose触发的核心事件列表:

事件功能
MG_EV_ACCEPT当监听连接接收到一个新服务器连接时触发。void *ev_data是远程端的union socket_address
MG_EV_CONNECT当mg_connect()创建了一个新出站连接时触发。void *ev_data是int *success。当success是0,则连接已经建立,否则包含一个错误码。
MG_EV_RECV新数据接收并追加到recv_mbuf结尾时触发。void *ev_data是int *num_received_bytes。时间处理器在nc->recv_mbuf检查接收数据,调用mbuf_remove()丢弃已处理的数据。请查看连接标识nc->flags(see struct mg_connection),并通过输出函数(如mg_send())写数据到远程端。

警告:Mongoose使用realloc()展开接收缓冲区,用户有责任从接收缓冲区的开头丢弃已处理的数据,请注意上面示例中的mbuf_remove()调用。

MG_EV_SEND: Mongoose已经写数据到远程,并且已经丢弃写入到mg_connection::send_mbuf的数据。void *ev_data是int *num_sent_bytes。

注意:Mongoose输出函数仅追加数据到mg_connection::send_mbuf。它们不做任何socket的写入操作。一个真实的IO是通过mg_mgr_poll()完成的。一个MG_EV_SEND事件仅仅是一个关于IO完成的通知。

MG_EV_POLL:在每次调用mg_mgr_poll()时发送到所有连接。该事件被用于做任何事情,例如,检查某个超时是否已过期并关闭连接或发送心跳消息等。

MG_EV_TIMER: 当mg_set_timer()调用后,发送到连接

TCP服务器示例

#include "mongoose.h"  // Include Mongoose API definitions

// Define an event handler function
static 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;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值