天天看點

Unix網絡程式設計——Mongoose開源項目源碼解讀(1):概述

簡述: 

Mongoose前身為shttpd,使用标準C/C++編寫而成,轉為嵌入式裝置設計的,支援跨平台的網絡伺服器庫。Mongoose實作了非阻塞式事件驅動API,支援TCP, UDP, HTTP, WebSocket, CoAP, MQTT。

Mongoose的三個基本結構體:

聲明與初始化事件管理器

建立連接配接,比如建立一個伺服器端的監聽套接字

輪詢處理:周遊所有套接字,接收新的連接配接請求,發送與接受資料,關閉連接配接,事件處理等

收發緩沖區

每個連接配接都有自己的收發緩沖區struct mbuf,當Mongoose 接收到資料時資料被追加到接收緩沖區并觸發一個MG_EV_RECV 事件。當需要發送資料時,隻需要使用 mg_send()或者mg_printf()将資料追加到發送緩沖區,當資料發送成功,Mongoose 将資料從發送緩沖區删除并發送一個MG_EV_SEND事件。當連接配接關閉時,觸發MG_EV_CLOSE事件。以下為mbuf的定義:

事件及事件處理函數

Mongoose 為連接配接、讀寫、關閉等都定義了事件,每個連接配接都有與其關聯的事件處理函數——該函數由使用者自身實作,該函數的原型如下:

典型的事件序列如下:

對于用戶端:MG_EV_CONNECT -> (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL …) -> MG_EV_CLOSE

對于服務端: MG_EV_ACCEPT -> (MG_EV_RECV, MG_EV_SEND, MG_EV_POLL …) -> MG_EV_CLOSE

以下為Mongoose的核心事件:

MG_EV_ACCEPT:當accept到一個新的連接配接請求時觸發該事件,ev_data 為socket_address 聯合體

MG_EV_CONNECT:當使用mg_connect() 建立連接配接套接字時觸發該事件,ev_data 為int *success,success為0表示成功,否則為失敗的errno

MG_EV_RECV:接收到新的資料,void *ev_data 是接收到的位元組數,接收到應該使用recv_mbuf來擷取資料,使用mg_send()發送資料。Mongoose 使用realloc來擴充接收緩沖區,但是需要由使用者删除已接收的資料——比如mbuf_remove()。

MG_EV_SEND:Mongoose 已經将(int *)ev_data 的資料寫到了遠端并将資料從send_mbuf中删除。mg_send()并不發送資料,隻是将資料追加到緩沖區,正真的IO操作由mg_mgr_poll()完成。

MG_EV_POLL:該事件被發送給所有的已連接配接套接字,它可以被用來作任何持續性的事務,比如檢查某個連接配接是否已經逾時或者關閉、過期,或者用來發送心跳消息。

MG_EV_TIMER:當mg_set_timer() 被調用時被用來發送給指定的connection

連接配接标記位

每個連接配接都有自己的标記位,比如當建立一個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 設定:

MG_F_SSL_HANDSHAKE_DONE SSL:隻有在SSL連接配接中才會設定,當SSL的握手完成時設定

MG_F_CONNECTING:在調用mg_connect() 後但是連接配接還沒有完成時設定

MG_F_LISTENING:為所有監聽套接字設定

MG_F_UDP:如果是UDP協定則設定

MG_F_IS_WEBSOCKET:如果是網絡套接字則設定

MG_F_WEBSOCKET_NO_DEFRAG:由使用者希望關閉自動的websocket架構碎片整理時設定

編譯選項:

Mongoose 源代碼由單一的c檔案構成,Mongoose 所支援的協定都由它提供。在編譯時Mongoose 可以去除不需要的功能以減小執行檔案的大小。比如可以使用-D MG_DISABLE_MQTT -D MG_DISABLE_COAP去除代碼中的MQTT和CoAP的支援代碼。

linux下的編譯樣例:

Mongoose 的使用樣例:

1.将mongoose.c 和mongoose.h拷貝到你的工程目錄下

2.使用mongoose提供的API編寫工程,例如my_app.c

3.編譯工程:cc my_app.c mongoose.c

繼續閱讀