mongoose 開源http庫


Mongoose是一個用C編寫的網絡庫。它為客戶端和服務器模式實現TCP,UDP,HTTP,WebSocket,CoAP,MQTT的事件驅動的非阻塞API。

設計理念:

Mongoose有三個基本的數據結構:

struct mg_mgr 是一個事件管理器,保存所有活動的連接
struct mg_connection 描述一個連接
struct mbuf 描述數據緩沖區(接收或發送的數據)

連接可能是listeninginboundoutbound通過調用mg_connect()創建outbound連接listening連接是由mg_bind()創建的inbound連接是通過listening連接接受后的連接。每個連接由struct mg_connection 結構描述,它具有許多字段,如套接字,事件處理函數,發送/接收緩沖區,標志等。

使用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. 通過調用循環創建一個事件mg_mgr_poll()循環:

for (;;) {
   mg_mgr_poll(&mgr, 1000);
 }

mg_mgr_poll()迭代所有套接字,接受新連接,發送和接收數據,關閉連接並調用相應事件的事件處理函數。

內存緩沖區

每個連接有一個發送和接收緩沖區,分別是struct mg_connection::send_mbuf 和 struct mg_connection::recv_mbuf當數據到達時,Mongoose將收到的數據附加到recv_mbuf並觸發MG_EV_RECV 事件。用戶可以通過調用輸出函數之一來發送數據,如 mg_send()mg_printf()輸出功能將數據附加到send_mbuf當Mongoose成功將數據寫入套接字時,它將丟棄數據 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:該指針指向事件特定的數據,它對於不同的事件具有不同的含義。例如,對於MG_EV_RECV事件, ev_dataint *指向從遠程對等體接收並保存到接收IO緩沖區中的字節數指針。ev_data每個事件描述的具體含義 特定於協議的事件通常ev_data指向具有協議特定信息的結構。

注意:對於應用程序特定數據,struct mg_connection具有void *user_data占位符。Mongoose不使用該指針。事件處理程序可以存儲任何類型的信息。

活動

Mongoose接受傳入連接,讀取和寫入數據,並在適當時調用每個連接的指定事件處理程序。這是一個典型的事件序列:

outbound 連接: MG_EV_CONNECT -> (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL...) -> MG_EV_CLOSE
inbound 連接: MG_EV_ACCEPT -> (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL ...) -> MG_EV_CLOSE

以下是由Mongoose觸發的核心事件列表(請注意,除了核心事件之外,每個協議都會觸發特定於協議的事件):

  • MG_EV_ACCEPT:當listening連接接受新的服務器連接時發送。void *ev_dataunion socket_address遠程對等體。

  • MG_EV_CONNECT:當由mg_connect() 創建新的出站連接時發送(無論失敗或成功)。void *ev_dataint *success。如果success 為0,則連接已建立,否則包含錯誤代碼。參見mg_connect_opt()代碼示例的功能。

  • MG_EV_RECV:收到新數據並將其附加到recv_mbuf。 void *ev_dataint *num_received_bytes。通常,事件處理程序應檢查接收到的數據nc->recv_mbuf,通過調用mbuf_remove()來丟棄已處理的數據,必要 時設置連接標志nc->flags(見struct mg_connection),並通過輸出函數寫入遠程對等體的數據 mg_send()

    警告:Mongoose用於realloc()擴展接收緩沖區。用戶有責任從接收緩沖區的開頭丟棄已處理的數據,請注意mbuf_remove()上述示例中的調用。

  • MG_EV_SEND:Mongoose已經向遠程對等體寫入了數據,並丟棄了數據mg_connection::send_mbufvoid *ev_dataint *num_sent_bytes

    注意:Mongoose輸出功能僅將數據附加到 mg_connection::send_mbuf。他們不做任何套接字寫。實際的IO由mg_mgr_poll()完成。一個MG_EV_SEND事件是關於IO已經完成的通知。

  • MG_EV_POLL:發送到每個調用的所有連接mg_mgr_poll()。此事件可用於執行任何內務處理,例如檢查某個超時是否過期並關閉連接或發送心跳消息等。

  • MG_EV_TIMER發送到連接如果mg_set_timer()被調用。

連接標志

每個連接都有一個flags位字段。一些標志由Mongoose設置,例如,如果用戶使用udp://1.2.3.4:5678 地址創建出站UDP連接,Mongoose將MG_F_UDP為該連接設置一個標志。其他標志僅由用戶事件處理程序設置,以告訴Mongoose如何行為。以下是由事件處理程序設置的連接標志列表:

  • MG_F_FINISHED_SENDING_DATA告訴Mongoose所有的數據已被追加到send_mbuf一旦Mongoose將其發送到套接字,連接將被關閉。
  • MG_F_BUFFER_BUT_DONT_SEND告訴Mongoose將數據附加到send_mbuf 但是發送它,因為數據將被稍后修改,然后通過清除MG_F_BUFFER_BUT_DONT_SEND標志來發送
  • MG_F_CLOSE_IMMEDIATELY 告訴Mongoose立即關閉連接,通常在發生錯誤后。
  • MG_F_USER_1MG_F_USER_2MG_F_USER_3MG_F_USER_4可以由開發者用來存儲特定於應用的狀態。

以下標志由Mongoose設置:

  • MG_F_SSL_HANDSHAKE_DONE 僅SSL,在SSL握手完成后設置。
  • MG_F_CONNECTINGmg_connect()連接處於連接狀態, 但連接尚未完成后設置。
  • MG_F_LISTENING 設置為所有偵聽連接。
  • MG_F_UDP 如果連接是UDP,請設置。
  • MG_F_IS_WEBSOCKET 設置如果連接是WebSocket連接。
  • MG_F_WEBSOCKET_NO_DEFRAG 如果用戶想要關閉自動WebSocket框架碎片整理,應由用戶設置。

構建選項

Mongoose源代碼包含在包含所有支持的協議(模塊)的功能的單個.c文件中。可以在編譯時禁用模塊,從而減少可執行文件的大小。這可以通過設置預處理程序標志來實現。此外,一些預處理器標志可用於調整內部Mongoose參數。

要在編譯期間設置預處理器標志,請使用-D <PREPROCESSOR_FLAG> 編譯器選項。例如,要禁用MQTT和CoAP,請編譯my_app.c這樣的應用程序(假定為UNIX系統):

 $ cc my_app.c mongoose.c -D MG_DISABLE_MQTT -D MG_DISABLE_COAP

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM