概述:
簡介:
Mongoose是c語言寫成的網絡庫。
它爲TCP、UDP、HTTP、WebSocket、CoAP、MQTT實現了事件驅動型的非阻塞api。其具備如下特性:
跨平臺:可在linux/unix macos QNX eCos Windows Android Iphone FreeRtos上運行
原生支持PicoTCP的嵌入式tcp/ip協議棧,支持LWIP嵌入式tcp/ip協議棧
單線程,異步,非阻塞核心與簡單的基於事件的API
可配置爲:
純TCP,純UDP SSL/TLS但雙向的客戶端和服務器;HTTP,WebSocket,MQTT,CoAP,DNS的客戶端和服務器,同時可做爲異步dns解析器。
在運行和佔用很小的內存,源代碼符合ISO C 和ISO c++
同時僅僅複製mongoose.c mongoose.h到你的工程便可完成整合。
Mongoose設計思路:
擁有3個基本類型的數據結構
1 struct mg_mgr;///事件管理器,保存全部的活動連接 2 struct mg_connection;///描述一個連接 3 struct mbuf;///接收和發送的數據
一個連接能夠是listening(監聽),outbound
(出站)或者inbound(入站)。
outbound
(出站)連接可經過調用mg_connect()產生。listening(監聽)連接可經過調用mg_bind()產生。(入站)inbound連接是由listening(監聽)連接所收到的連接。每一個連接都使用struct mg_connection進行描述,此結構中有,socket,事件處理函數,發送/接收緩衝區,以及其餘標誌。
使用mongoose的應用程序應該遵循事件驅動的標準模式:
1 struct mg_mgr mgr; 2 mg_mgr_init(&mgr, NULL);////建立並初始化事件管理器 3 struct mg_connection *c = mg_bind(&mgr, "80", ev_handler_function); 4 mg_set_protocol_http_websocket(c);///建立連接,上面2行代碼是服務器應用程序建立的監聽連接 5 for (;;) { 6 mg_mgr_poll(&mgr, 1000); 7 }///經過調用mg_mgr_pool()建立事件循環。
mg_mgr_poll()遍歷全部的套接字,接受新連接,發送,接收數據,關閉連接。併爲各自的事件調用事件處理函數。有關完整實例,可參考TCP echo server的使用實例。
內存緩衝區:
每一個連接都有接收和發送的數據緩衝區:
struct mg_connection::recv_mbuf,
struct mg_connection::send_mbuf
.當接收到數據的時候Mongoose將數據追加到recv_mbuf,而且觸發MG_EV_RECV事件。用戶可調用
mg_send(),mg_printf()
這些輸出函數將數據追加到send_mbuf中併發送回去。當mongoose成功地向socket寫入數據的時候,mongoose會將此數據從send_mbuf中丟棄,併發送MG_EV_SEND事件。當連接關閉的時候,發送MG_EV_CLOSE事件。
![](http://static.javashuo.com/static/loading.gif)
事件處理函數:
每一個連接都有其與之相關的事件處理函數。此事件處理函數由用戶本身實現。事件處理函數是mongoose程序的關鍵,由於其定義了應用程序的具體行爲。事件處理函數以下:
1 static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { 2 switch (ev) { 3 /* Event handler code that defines behavior of the connection */ 4 ... 5 } 6 } 7 ////////////////////////////////////解讀//////////////////////////////////////////// 8 struct mg_connection *nc;///鏈接所接收到的事件 9 int ev;///事件編號,可在mongoose.h中找到。當(入站)連接收到數據的時候,ev=MG_EV_RECV 10 void *ev_data;///此指針指向事件特定數據,對於不一樣事件有不一樣含義。每一個事件都描述了ev_data的具體含義。特定協議的事件ev_data一般指向包含協議特定信息的結構。 11 /* 12 MG_EV_RECV事件:ev_data是一個int *,保存從連接中接收,並保存到接收IO緩衝區中字節數 13 struct mg_connection 有應用程序特定數據佔位符void *user_data。 14 mongoose不適用指針,事件處理函數user_data這個指針,事件處理函數可在此存儲任何信息。 15 */
事件:php
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:監聽連接接收到一個新的連接,void *ev_data 是遠程連接的union socket_addres
MG_EV_ACCEPT:監聽連接接收到一個新的連接,void *ev_data 是遠程連接的union socket_addres
MG_EV_CONNECT:mg_connect()建立一個出站連接(不管mg_connect()調用是否成功),void *ev_data 是 int *success.
success=0,連接創建成功,不然連接創建失敗,幷包含一個錯誤碼。可查看mg_connect_opt()查看
代碼實例。
MG_EV_RECV:接收到新數據,並將數據追加到recv_mbuf.void * ev_data是 int *num_received_bytes.一般狀況下事件處理程序應該在nc->recv_mbuf()檢查接受到的數據,經過調用mbuf_remove()丟棄處理後的數據,必要時設置連接標誌nc->flags(查看struct mg_connection).使用mg_send()向遠程連接點發送數據。
mongoose使用realloc()來擴展接收緩衝區,從接收緩衝區的開頭丟棄處理過的數據是用戶的責任。注意上面的mbuf_remove().
MG_EV_SEND:mongoos向遠程鏈接點寫入數據,並將mg_connectiong::send_mbuf中數據丟棄。void *ev_data是int *num_sent_bytes即發送的字節數。mongoose輸出函數僅僅是將數據追加到sned_mbuf,不作任何socket寫操做。實際的IO寫操做是由mg_mgr_pool()完成,MG_EV_SEND僅僅是一個關於IO操做已經完成的通知。
MG_EV_POLL:將每次調用mg_mgr_poll()發送到每一個連接。此事件可作任何事情。例如檢測某個超時連接是否關閉,或者發送心跳。
MG_EV_TIMER: 向某個調用mg_set_timer()的連接發送
連接flags:
每一個連接都有flasg位域。有些flags是由mongoose設置的,例如若是用戶使用udp://1.2.3.4:5678建立一個出站的UDP連接。mongoose會爲此連接設置MG_F_UDP標記。其餘標誌只能由用戶事件處理程序設置,告訴mongoose作何種操做。下面是由事件處理程序設置的連接flags列表:
MG_F_FINISHED_SENDING_DATA:告訴mongoose全部數據已經追加到send_mbuf,只要mongoose將數據寫入socket,此連接就會關閉。
MG_F_BUFFER_BUT_DONT_SEND:告訴mongoose追加
數據到send_mbuf,但數據要立刻發送,由於此數據稍後會被修改。而後經過清除
MG_F_BUFFER_BUT_DONT_SEND標誌將數據發送出去。
MG_F_CLOSE_IMMEDIATELY:告訴mongoose當即關閉連接 ,一般在產生錯誤後發送此事件。
MG_F_CLOSE_IMMEDIATELY:告訴mongoose當即關閉連接 ,一般在產生錯誤後發送此事件。
MG_USER_1,MG_USER_2,MG_USER_3,MG_USER_4:開發者可用它來存儲特定應用程序的狀態
下面是由mongoose設置的flags:
MG_F_SSL_HANDSHAKE_DONE:僅使用ssl,在ssl握手完成時設置
MG_F_CONNECTING:在mg_connect()調用後連接處於連接狀態但未完成連接時設置。
MG_F_LISTENING:設置全部監聽連接
MG_F_LISTENING:設置全部監聽連接
MG_F_UDP:連接是udp時設置。
MG_F_WEBSOCKET:連接是websocket時設置。
MG_F_WEBSOCKET_NO_DEFRAG:若是用戶想關閉websocket的自動幀碎片整理功能,則由用戶設置此標記。
MG_F_WEBSOCKET_NO_DEFRAG:若是用戶想關閉websocket的自動幀碎片整理功能,則由用戶設置此標記。
編譯選項:
mongoose源代在一個.c文件中,此文件包含全部受支持協議(模塊)的功能。能夠在編譯時設置預處理器編制來禁用模塊,以減小可執行文件的大小。一些預處理器標誌能夠調整mongoose的內部參數。在編譯期間可以使用-D<PREPROCESSOR_FLAG>設置編譯器選項。例如要禁用MQTT和CoAP,編譯應用程序my_app.c在linux下用:
啓用標誌 | |
Flag | 介紹 |
MG_ENABLE_SSL | 啓用SSL/TLS支持(OpenSSL API) |
MG_ENABLE_IPV6 | 啓用IPV6支持 |
MG_ENABLE_MQTT | 啓用MQTT客戶端(默認狀況下設置爲0表示禁用) |
MG_ENABLE_MQTT_BROKER | 啓用MQTT broker |
MG_ENABLE_DNS_SERVER | 啓用DNS服務器 |
MG_ENABLE_COAP | 啓用CoAP協議 |
MG_ENABLE_HTTP | 啓用HTTP協議支持(默認狀況下,設置0表示禁用) |
MG_ENABLE_HTTP_CGI | 啓用CGI |
MG_ENABLE_HTTP_SSI | 啓用Server Side |
MG_ENABLE_HTTP_SSI_EXEC | 啓用SSI exec操做 |
MG_ENABLE_HTTP_WEBDAV | 啓用HTTP的WebDAV擴展 |
MG_ENABLE_HTTP_WEBSOCKET | 啓用HTTP的WebSocket擴展,默認狀況下 設置0禁止 |
MG_ENABLE_BROADCAST | 啓用mg_broadcast()API |
MG_ENABLE_GETADDRINFO | 啓用在mg_resolve2()中的getaddrinfo() |
MG_ENABLE_THREADS | 啓用在mg_start_thread()API |
禁用標誌 | |
MG_DISABLE_HTTP_DIGEST_AUTH | 禁用HTTP摘要(MD5)受權支持 |
CS_DISABLE_SHA1 | 禁用WebSocket中的SHA1支持 |
CS_DISABLE_MD5 | 禁用HTTP鑑權中的MD5支持 |
MG_DISABLE_HTTP_KEEP_ALIVE | 用於嵌入式系統節省資源 |
平臺相關選項(mongoose會盡量的檢測目標平臺,可是在某些狀況下,必須明確聲明目標平臺的部分特性) | |
MG_CC3200 | 爲TICC3200板子啓用工做區 |
MG_ESP8266 | 爲ESP8266板子添加RTOS_SDK來指定RTOS_SDK風格 |
可調整 | |
MG_MALLOC,MG_CALLOC,MG_REALLOC,MG_FREE | 容許使用開發者自定義的內存分配處理函數 -DMG_MALLCO=my_malloc |
MG_USE_READ_WRITE | 設置後,將recv的調用替換爲read,send。從而容許向事件管理器添加任何類型的文件描述符(文件,串行設備) |
MG_SSL_CRYPTO_MODERN,MG_SSL_CRYPTO_OLD | 選擇modern或者old密碼替換默認的Intermediate密碼。在下面網址查看各類密碼形式的詳細信息 https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations |
MG_USER_FILE_FUNCTIONS | 容許開發者經過定義本身的mg_stat,mg_fopen,mg_open,mg_fread,mg_fwrite去自定義文件操做函數 |
實例:TCP echo server
複製mongoose.c mongoose.h到你的工程;在my_app.c中使用mongoose的API寫代碼。編譯代碼
$$cc my_app.c mongoose.c
1 /********************my_app.c*******************/ 2 #include "mongoose.h" // Include Mongoose API definitions 3 // Define an event handler function 4 static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { 5 struct mbuf *io = &nc->recv_mbuf; 6 switch (ev) { 7 case MG_EV_RECV: 8 // This event handler implements simple TCP echo server 9 mg_send(nc, io->buf, io->len); // Echo received data back 10 mbuf_remove(io, io->len); // Discard data from recv buffer 11 break; 12 default: 13 break; 14 } 15 } 16 17 int main(void) { 18 struct mg_mgr mgr; 19 mg_mgr_init(&mgr, NULL); // Initialize event manager object 20 // Note that many connections can be added to a single event manager 21 // Connections can be created at any point, e.g. in event handler function 22 mg_bind(&mgr, "1234", ev_handler); // Create listening connection and add it to the event manager 23 for (;;) { // Start infinite event loop 24 mg_mgr_poll(&mgr, 1000); 25 } 26 mg_mgr_free(&mgr); 27 return 0; 28 }
HTTP:
實例一:HTTP server
1,使用mg_bind()或者mg_bind_opt()建立立監聽連接
2.調用mg_set_protocol_http_websocket()去監聽全部連接。此函數附加了一個內置的http事件處理事件,用於解析並觸發特定的HTTP事件。例如當HTTP請求被徹底緩衝時,內置的HTPP處理程序將解析請求並使用MG_EV_HTTP_REQUEST事件調用用戶定義的事件處理函數,並將HTTP請求解析爲事件數據。
3.建立事件處理函數。事件處理程序接收全部的事件(低級別TCP事件(MG_EV_RECV)和高級別HTTP事件(MG_EV_HTTP_REQUEST))。一般事件處理函數應該只處理高級別事件MG_EV_HTTP_REQUEST
下面是HTTP server的實例代碼,其中省略了錯誤檢查
1 // Copyright (c) 2015 Cesanta Software Limited 2 // All rights reserved 3 4 #include "mongoose.h" 5 6 static const char *s_http_port = "8000"; 7 static struct mg_serve_http_opts s_http_server_opts; 8 9 static void ev_handler(struct mg_connection *nc, int ev, void *p) { 10 if (ev == MG_EV_HTTP_REQUEST) { 11 mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); 12 } 13 } 14 15 int main(void) { 16 struct mg_mgr mgr; 17 struct mg_connection *nc; 18 19 mg_mgr_init(&mgr, NULL); 20 printf("Starting web server on port %s\n", s_http_port); 21 nc = mg_bind(&mgr, s_http_port, ev_handler); 22 if (nc == NULL) { 23 printf("Failed to create listener\n"); 24 return 1; 25 } 26 27 // Set up HTTP server parameters 28 mg_set_protocol_http_websocket(nc); 29 s_http_server_opts.document_root = "."; // Serve current directory 30 s_http_server_opts.enable_directory_listing = "yes"; 31 32 for (;;) { 33 mg_mgr_poll(&mgr, 1000); 34 } 35 mg_mgr_free(&mgr); 36 37 return 0; 38 }
實例二:HTTP Client
1:使用mg_connect_http()建立出站連接
2:建立事件處理函數用於處理MG_EV_HTTP_REPLY事件
HTTP事件:
正如在概述中所討論的,mg_set_protocol_http_websocket()函數解析傳入的數據,將其視爲HTTP或WebSocket,並觸發高級HTTP或WebSocket事件。下面是一個特定於HTTP的事件列表:
MG_EV_HTTP_REQUEST:收到一個http請求,解析後的請求
整理爲struct http_message結構,並經過void * ev_data指針傳遞。
MG_EV_HTTP_REPLY:收到一個http迴應,解析後的迴應整理爲struct http_message結構,並經過void * ev_data指針傳遞。
MG_EV_HTTP_MULTIPART_REQUEST:收到一個分多個包傳遞的http請求,在http的body開始解析前發送此事件。在此事件後用戶會收到一些列的MG_HTTP_PART_BEGIN/DATA/END請求。這也是最後一次訪問標頭和http中其餘請求字段。
MG_EV_HTTP_MULTIPART_REQUEST:收到一個分多個包傳遞的http請求,在http的body開始解析前發送此事件。在此事件後用戶會收到一些列的MG_HTTP_PART_BEGIN/DATA/END請求。這也是最後一次訪問標頭和http中其餘請求字段。
MG_EV_HTTP_CHUNK:收到一個http編碼塊,解析後的http應答整理爲struct http_message結構,並經過void * ev_data指針傳遞。http_message::body將包含從新組裝的不完整body塊。http_message::body伴隨着每一個新塊的到達而增加,此過程可能消耗大量內存。事件處理函數可在塊到來的時候處理body,並經過設置在mg_connection::flags設置MG_F_DELETE_CHUNK標記來告知mongoose去刪除已經解析處理過的body塊。(若是事件處理函數沒有告知mongoose去刪除已經處理過的body)當接收到最後一個0數據塊的時候,mongoose發送MG_F_HTTP_REPLY事件並帶有重組的完整的body.
MG_F_HTTP_PART_BEGIN:開始接收 分包傳遞的消息的一部分消息,並在mg_http_multipart中國傳遞額外參數。
MG_F_HTTP_PART_DATA:開始接收 分包傳遞的消息的新數據部分沒有額外的表頭可用只有
數據和數據大小
MG_F_HTTP_PART_END:收到最後一個邊界,相似可能用來找到包的結尾。須要注意的是mongoose在編譯的時候應該設置MG_ENABLE_HTTP_MULTIPART去使能多部分事件。
Serving files:
mg_serve_http()函數使得從文件系統提供文件變得時分簡單。通常來此函數是http server實現的用於提供cgi,ssl等靜態文件的。它的行爲合併到了struct mg_serve_http_opts結構的選項列表中.mg_serve_http()功能的完整列表可參考struct mg_serve_http_opts.
爲了建立一個服務於當前目錄中的靜態文件的web服務器。按以下方式實現事件處理器函數:
1 static void ev_handler(struct mg_connection *c, int ev, void *ev_data) { 2 if (ev == MG_EV_HTTP_REQUEST) { 3 struct mg_serve_http_opts opts; 4 5 memset(&opts, 0, sizeof(opts); // Reset all options to defaults 6 opts.document_root = "."; // Serve files from the current directory 7 8 mg_serve_http(c, (struct http_message *) ev_data, s_http_server_opts); 9 } 10 }
有時候不須要完整的靜態web服務器。例如在RESTful的服務器上工做,若是某些端點必須返回靜態文件的內容,可以使用簡單的mg_http_serve_file()函數
1 static void ev_handler(struct mg_connection *c, int ev, void *ev_data) { 2 switch (ev) { 3 case MG_EV_HTTP_REQUEST: { 4 struct http_message *hm = (struct http_message *) ev_data; 5 mg_http_serve_file(c, hm, "file.txt", 6 mg_mk_str("text/plain"), mg_mk_str("")); 7 break; 8 } 9 ... 10 } 11 }
CGI:
cgi是一種簡單的動態內容生成機制。爲了去使用cgi,調用mg_serve_http()函數並對cgi文件使用.cgi擴展名便可。更準確地說,匹配struct mg_serve_opts中cgi_file_pattern模式的文件都視爲cgi,若是cgi_file_pattern是NULL則**.cgi$或者**.php$均可使用。
若是mongoose將一個文件看做是cgi文件,它會去執行此文件,並其輸出發送回client.所以cgi文件必須是可執行的。若是同時使用PHP和Perl CGIs,那麼在各自cgi腳本的第一行必須是#!/path/to/php-cgi.exe和
#!/path/to/perl.exe.能夠爲全部的cgi腳本硬編碼到cgi解釋器的路徑而不考慮shebang line。爲此在mg_serve_http_opts中設置cgi_interpreter.注意php腳本必須使用php-cgi.exe做爲cgi解析器而不是php.exe
opts.cgi_interpreter = "C:\\ruby\\ruby.exe";
在cgi處理程序中,咱們沒有顯式地使用系統調用waitpid()來獲取殭屍進程。相反咱們將SIGCHLD處理程序設置爲SIG_IGN.其致使殭屍進程會自動獲取。入股全部的SIGCHLD被忽略,並非全部的操做系統都會獲取殭屍進程。
SSI:
文件上傳:
爲了實現文件上傳,使用以下html
<form method="POST" action="/upload" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="Upload"> </form>
上傳文件會經過POST請求將文件發送到/upload目錄。HTTP的body將會包含文件內容的多部分編碼緩衝區。爲保存文件使用以下:
1 struct mg_str cb(struct mg_connection *c, struct mg_str file_name) { 2 // Return the same filename. Do not actually do this except in test! 3 // fname is user-controlled and needs to be sanitized. 4 return file_name; 5 } 6 7 void ev_handler(struct mg_connection *c, int ev, void *ev_data) { 8 switch (ev) { 9 ... 10 case MG_EV_HTTP_PART_BEGIN: 11 case MG_EV_HTTP_PART_DATA: 12 case MG_EV_HTTP_PART_END: 13 mg_file_upload_handler(c, ev, ev_data, cb); 14 break; 15 } 16 }
使能SSL(HTTPS):
在http服務器端使能ssl須要按照以下步驟:
1.獲取ssl證書和私鑰文件
2.聲明struct mg_bind_opts,初始化化ssl_cert和ssl_key
3.使用mg_bind_opt()去建立監聽socket
實例:(更多介紹:查看examples中的https server 實例)
1 int main(void) { 2 struct mg_mgr mgr; 3 struct mg_connection *c; 4 struct mg_bind_opts bind_opts; 5 6 mg_mgr_init(&mgr, NULL); 7 8 memset(&bind_opts, 0, sizeof(bind_opts)); 9 bind_opts.ssl_cert = "server.pem"; 10 bind_opts.ssl_key = "key.pem"; 11 12 // Use bind_opts to specify SSL certificate & key file 13 c = mg_bind_opt(&mgr, "443", ev_handler, bind_opts); 14 mg_set_protocol_http_websocket(c); 15 16 ... 17 }
Digest身份認證
mongoose有一個內置的digest(md5)認證支持。爲了啓用digest認證,須要再保護目錄中建立一個.htpasswd文件。此文件應該採用apache的htdigest使用程序的格式。
你可使用Apache的htdigest實例,或者mongoose在
https://www.cesanta.com/binary.htm預構建一個二進制並添加新用戶到這個文件。
mongoose -A /path/to/.htdigest mydomain.com joe joes_password
通用API參考:
1 struct http_message { 2 struct mg_str message; /* Whole message: request line + headers + body */ 3 struct mg_str body; /* Message body. 0-length for requests with no body */ 4 5 /* HTTP Request line (or HTTP response line) */ 6 struct mg_str method; /* "GET" */ 7 struct mg_str uri; /* "/my_file.html" */ 8 struct mg_str proto; /* "HTTP/1.1" -- for both request and response */ 9 10 /* For responses, code and response status message are set */ 11 int resp_code; 12 struct mg_str resp_status_msg; 13 14 /* 15 * Query-string part of the URI. For example, for HTTP request 16 * GET /foo/bar?param1=val1¶m2=val2 17 * | uri | query_string | 18 * 19 * Note that question mark character doesn't belong neither to the uri, 20 * nor to the query_string 21 */ 22 struct mg_str query_string; 23 24 /* Headers */ 25 struct mg_str header_names[MG_MAX_HTTP_HEADERS]; 26 struct mg_str header_values[MG_MAX_HTTP_HEADERS]; 27 };///HTTP消息 28 struct websocket_message { 29 unsigned char *data; 30 size_t size; 31 unsigned char flags; 32 };///websocket消息 33 struct mg_http_multipart_part { 34 const char *file_name; 35 const char *var_name; 36 struct mg_str data; 37 int status; /* <0 on error */ 38 void *user_data; 39 };///HTTP分包部分 40 struct mg_ssi_call_ctx { 41 struct http_message *req; /* The request being processed. */ 42 struct mg_str file; /* Filesystem path of the file being processed. */ 43 struct mg_str arg; /* The argument passed to the tag: <!-- call arg -->. */ 44 };///SSI調用上下文 45 void mg_set_protocol_http_websocket(struct mg_connection *nc); 46 void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri, 47 const char *extra_headers); 48 void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, 49 const char *host, const char *protocol, 50 const char *extra_headers); 51 void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, 52 const char *host, const char *protocol, 53 const char *extra_headers, const char *user, 54 const char *pass); 55 void mg_send_websocket_handshake3v(struct mg_connection *nc, 56 const struct mg_str path, 57 const struct mg_str host, 58 const struct mg_str protocol, 59 const struct mg_str extra_headers, 60 const struct mg_str user, 61 const struct mg_str pass); 62 struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, 63 MG_CB(mg_event_handler_t event_handler, 64 void *user_data), 65 const char *url, const char *protocol, 66 const char *extra_headers); 67 struct mg_connection *mg_connect_ws_opt( 68 struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), 69 struct mg_connect_opts opts, const char *url, const char *protocol, 70 const char *extra_headers); 71 void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, 72 const void *data, size_t data_len); 73 void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, 74 const struct mg_str *strings, int num_strings); 75 void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, 76 const char *fmt, ...); 77 int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, 78 int is_form_url_encoded); 79 extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], 80 const size_t *msg_lens, uint8_t *digest); 81 extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], 82 const size_t *msg_lens, uint8_t *digest); 83
http server端API參考:
1 int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req); 2 /**解析http消息,若是is_req=1 此消息是http請求,is_req=0 此消息是http迴應 3 *返回解析的字節數 若是http消息不完整則返回0 若是解析出錯,則返回負數*/ 4 struct mg_str *mg_get_http_header(struct http_message *hm, const char *name); 5 /**搜索並返回解析後的http消息hm中的表頭名稱,若是沒有找到標頭,則返回NULL 6 *實例:struct mg_str *host_hdr = mg_get_http_header(hm, "Host");*/ 7 int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, 8 size_t buf_size); 9 /**解析http頭hdr,查找變量var_name並將其值存儲到buf中,若是沒有找到變量,返回0不然返回非0。此函數用於解析cookies驗證頭等。若是成功則返回變量值的長度,若是buf緩衝區不夠大,或者沒有找到此變量則返回0 10 char user[20]; 11 struct mg_str *hdr = mg_get_http_header(hm, "Authorization"); 12 mg_http_parse_header(hdr, "username", user, sizeof(user)); 13 */ 14 int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len, 15 char *pass, size_t pass_len); 16 /*獲取並解析受權,若是沒有找到受權頭或者mg_parse_http_basic_auth解析結果頭失敗*/ 17 int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len, 18 char *pass, size_t pass_len); 19 /*解析受權,如受權類型不是Basic或者出現其餘錯誤(如用於base64編碼的用戶密碼不對)基本頭返回-1*/ 20 size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, 21 size_t var_name_len, char *file_name, 22 size_t file_name_len, const char **chunk, 23 size_t *chunk_len); 24 /*解析包含多部分表單數據庫的緩衝區buf,buf_len,將塊名存儲在var_name,var_name_len緩衝區中。若是塊是上傳文件,那麼file_name,file_name_len將會被一個上傳的文件名填充。chunk,chunk_len指向塊數據。返回要跳到下一個塊的字節數,若是沒有更多塊則返回0*/ 25 int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, 26 size_t dst_len); 27 /*獲取Http表單變量。從buf獲取變量名,到指定dst指定長度dst_len的緩衝區。目的地址老是0終止,返回獲取到的變量的長度,若是沒有找到變量,則返回0.buf必須是有效的url編碼緩衝區。若是dst長度過小或者發生錯誤返回負數*/ 28 29 //此結構定義了mg_serve_http()的工做方式,最佳是設置須要的,其他爲NULL 30 struct mg_serve_http_opts { 31 const char *document_root;///web根目錄路徑 32 const char *index_files;///索引文件列表,默認是"" 33 /* 34 per_directory_auth_file =NULL表示禁用身份驗證 35 per_directory_auth_file =".htpasswd" 要使用身份認證來保護目錄,而後在任何目錄建立使用 digest認證的.htpasswd文件。使用mongoose web服務器二進制文件或 者Apache的htpasswd實例建立/操做密碼文件 36 確保auth_domain是一個有效的域 37 */ 38 const char *per_directory_auth_file; 39 const char *auth_domain;//受權域。即web服務器的域名 40 /* 41 global_auth_file = NULL 禁用身份認證 42 一般只保護document_root根目錄選定的目錄。若是對web服務器的全部訪問都必須通過身份驗證, 無論URI是什麼,將此選項設置爲密碼文件的路徑。此文件的格式與.htpasswd的格式同樣,並把此 文件放在document_root根目錄以外,以防他人獲取到此文件 43 */ 44 const char *global_auth_file; 45 const char *enable_directory_listing;//設置爲"no"禁用目錄列表,默認啓用 46 const char *ssi_pattern;///ssi匹配模式 源碼有詳細介紹 47 const char *ip_acl;///ip_acl=NULL表示全部IP均可連接 48 #if MG_ENABLE_HTTP_URL_REWRITES 49 const char *url_rewrites;/////源碼有詳細介紹 50 #endif 51 const char *dav_document_root;///DAV的根目錄,dav_document_root=NULL 則DAV請求失敗 52 const char *dav_auth_file;//DAV密碼文件,dav_auth_file=NULL 則DAV請求失敗 dav_auth_file="-" 禁用DAV鑑權 53 const char *hidden_file_pattern;///文件隱藏的Glob模式 54 const char *cgi_file_pattern;///cgi_file_pattern != NULL 則使能cgi,即此目錄下知足 **.cgi$|**.php$"都視爲cgi文件 55 const char *cgi_interpreter;///若是不是NULL,請忽略CGI腳本hashbang並使用這個解釋器 56 const char *custom_mime_types; 57 /*Comma-separated list of Content-Type overrides for path suffixes,".txt=text/plain; charset=utf-8,.c=text/plain"e.g.*/ 58 const char *extra_headers;///添加到每一個http相應的額外的header,要啓用CORS,請將此設置爲"Access-Control-Allow-Origin: *"。 59 } 60 void mg_serve_http(struct mg_connection *nc, struct http_message *hm, 61 struct mg_serve_http_opts opts); 62 /*根據opts的內容,提供特定的http請求*/ 63 void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, 64 const char *path, const struct mg_str mime_type, 65 const struct mg_str extra_headers); 66 /*提供具備給定MIME類型和可選extra_headers頭的特定文件*/ 67 typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc, 68 struct mg_str fname);///mg_file_upload_handler()的回調函數原型 69 void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, 70 mg_fu_fname_fn local_name_fn 71 MG_UD_ARG(void *user_data)); 72 /*文件上傳處理程序。這個處理程序能夠用最少的代碼實現文件上傳.此程序處理MG_EV_HTTPPART事件並保存文件數據到本地。local_name_fn將以客戶端提供的名字調用並以指望的本地文件名稱打開。若是返回NULL將終止文件上傳(客戶端獲得403),若是返回不是NULL,返回的字符串必須是堆分配的,且調用方須要釋放這些字符串。異常狀況:返回徹底相同的字符串, 73 */ 74 void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, 75 MG_CB(mg_event_handler_t handler, 76 void *user_data)); 77 /*爲nc註冊回調函數,若是註冊了回調函數,其會被調用歐冠,而不是調用mg_bind()中提供的回調函數*/ 78 struct mg_http_endpoint_opts { 79 void *user_data; 80 /*受權域 (realm) */ 81 const char *auth_domain; 82 const char *auth_file; 83 }; 84 void mg_register_http_endpoint_opt(struct mg_connection *nc, 85 const char *uri_path, 86 mg_event_handler_t handler, 87 struct mg_http_endpoint_opts opts); 88 int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, 89 FILE *fp); 90 /*根據打開的密碼文件驗證HTTP請求。若是通過身份驗證,返回1,不然返回0*/ 91 int mg_check_digest_auth(struct mg_str method, struct mg_str uri, 92 struct mg_str username, struct mg_str cnonce, 93 struct mg_str response, struct mg_str qop, 94 struct mg_str nc, struct mg_str nonce, 95 struct mg_str auth_domain, FILE *fp); 96 /*對打開的密碼文件驗證給定的響應參數。若是通過身份驗證,返回1,不然返回0。 97 由 mg_http_check_digest_auth().調用 98 */ 99 void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len); 100 /* 101 使用組塊HTTP編碼向客戶端發送大小爲len的緩衝區buf.這個函數首先將 發送緩衝區大小(16進制)+換行符+緩衝區+換行符發出。例如,mg_send_http_chunk(nc,「foo」,3)將把 "3\r\nfoo\r\n"字符串追加到nc->send_mbuf輸出IO緩衝區 102 HTTP頭「傳輸編碼:塊化」應該在使用此函數以前發送 103 不要忘記在響應結束時發送一個空塊,告訴客戶端全部內容都已發送 104 */ 105 void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...); 106 /*發送一個printf格式的HTTP塊。功能相似於mg_send_http_chunk()。*/ 107 void mg_send_response_line(struct mg_connection *nc, int status_code, 108 const char *extra_headers); 109 /*發送響應狀態行。若是extra_headers不是NULL,那麼extra_headers也會在響應行以後發送。extra_headers不能以新行結束*/ 110 void mg_http_send_error(struct mg_connection *nc, int code, const char *reason); 111 /*發送一個錯誤的迴應。若是緣由爲空,消息將從錯誤代碼中推斷出來(若是支持的話)*/ 112 void mg_http_send_redirect(struct mg_connection *nc, int status_code, 113 const struct mg_str location, 114 const struct mg_str extra_headers); 115 /*發送一個重定向響應。status_code應該是301或302,位置指向新位置。若是extra_headers不是空的,那麼extra_headers也會在響應行以後發送。extra_headers不能以新行結束。*/ 116 void mg_send_head(struct mg_connection *n, int status_code, 117 int64_t content_length, const char *extra_headers); 118 /*發送響應行和標題。這個函數用status_code發送響應行,並自動發送一個標題:"Content-Length"或 "Transfer-Encoding"。若是content_length爲負,則發送「Transfer-Encoding: chunked」報頭,不然發送「Content-Length」報頭。若是轉換編碼被分割,那麼消息體必須使用mg_send_http_chunk()或mg_printf_http_chunk()函數發送。不然,必須使用mg_send()或mg_printf()。額外的標題能夠經過extra_headers設置。注意,extra_headers不能被一個新的行終止*/ 119 void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...); 120 /*發送一個打印格式的HTTP塊,轉義HTML標記*/ 121 void mg_http_reverse_proxy(struct mg_connection *nc, 122 const struct http_message *hm, struct mg_str mount, 123 struct mg_str upstream); 124 /*將給定的請求代理給給定的上游http服務器.掛載中的路徑前綴將被剝離到上游服務器請求的路徑,例如若是掛載爲/api,上游爲 http://localhost:8001/foo 那麼向/api傳入的請求將傳入到 http://localhost:8001/foo/bar*/ 125 126
client 端API參考:
1 struct mg_connection *mg_connect_http( 2 struct mg_mgr *mgr, 3 MG_CB(mg_event_handler_t event_handler, void *user_data), const char *url, 4 const char *extra_headers, const char *post_data); 5 /*建立出站HTTP鏈接的助手函數 6 url是要獲取的url。它必須被正確地url編碼,例如沒有空格,等等.默認狀況下,mg_connect_http()發送鏈接和主機頭 7 extra_headers是一個額外的HTTP頭:"User-Agent: my-app\r\n" 8 若是post_data爲空,則建立一個GET請求。不然,將使用指定的POST數據建立POST請求。 9 注意,若是要提交的數據是表單提交,那麼應該相應地設置Content-Type報頭(參見下面的示例)。 10 nc1 = mg_connect_http(mgr, ev_handler_1, "http://www.google.com", NULL, 11 NULL); 12 nc2 = mg_connect_http(mgr, ev_handler_1, "https://github.com", NULL, NULL); 13 nc3 = mg_connect_http( 14 mgr, ev_handler_1, "my_server:8000/form_submit/", 15 "Content-Type: application/x-www-form-urlencoded\r\n", 16 "var_1=value_1&var_2=value_2"); 17 */ 18 struct mg_connection *mg_connect_http_opt( 19 struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), 20 struct mg_connect_opts opts, const char *url, const char *extra_headers, 21 const char *post_data); 22 /*建立出站HTTP鏈接的助手函數.與mg_connect_http基本相同,但容許提供額外的參數(例如SSL參數)*/ 23 int mg_http_create_digest_auth_header(char *buf, size_t buf_len, 24 const char *method, const char *uri, 25 const char *auth_domain, const char *user, 26 const char *passwd); 27 /*爲客戶機請求建立摘要身份驗證頭*/