首页 > 其他分享 >C网络库mongoose

C网络库mongoose

时间:2023-03-14 23:12:17浏览次数:61  
标签:MG HTTP struct mg 网络 mgr mongoose EV

 

官方链接:https://github.com/cesanta/mongoose

[C++]-网络库mongoose简介_alwaysrun的博客-CSDN博客_c++ mongoose

Mongoose-基于C的Web服务器介绍和使用 - 百度文库

https://blog.csdn.net/qianlixiaomage/article/details/105568130

 

Mongoose库设计理念缓冲区事件处理函数事件连接flagsHttp示例RESTful Server

Mongoose是C语言网络库,为TCP、UDP、HTTP、WebSocket、CoAP、MQTT实现了事件驱动型的非阻塞api。

Mongoose库

Mongoose是出名的嵌入式网络编程库(https://github.com/cesanta/mongoose);只需微小的静态和运行时占用空间,功能包括:

  • 跨平台:适用于Linux / UNIX,MacOS,QNX,eCos,Windows,Android,iPhone,FreeRTOS
  • PicoTCP嵌入式TCP / IP堆栈LWIP嵌入式TCP / IP堆栈的本机支持
  • 适用于各种嵌入式板卡:TI CC3200,TI MSP430,STM32,ESP8266;在所有基于Linux的板上,例如Raspberry PI,BeagleBone等
  • 具有简单的基于事件的API的单线程,异步,非阻塞内核
  • 内置协议:
    • 普通TCP,普通UDP,SSL / TLS(单向或双向),客户端和服务器
    • HTTP客户端和服务器
    • WebSocket客户端和服务器
    • MQTT客户端和服务器
    • CoAP客户端和服务器
    • DNS客户端和服务器
    • 异步DNS解析器
  • 微小的静态和运行时占用空间
  • 源代码均符合ISO C和ISO C ++
  • 易于集成:只需将mongoose.cmongoose.h文件复制到构建树中

 

设计理念

Mongoose的三个基本数据结构:

 
  struct mg_mgr;///事件管理器,保存所有的活动链接   struct mg_connection;///描述一个链接   struct mbuf;///接收和发送的数据
 
 

每个链接都使用mg_connection进行描述,一个连接可以是:

  • outbound(出站)链接:通过调用mg_connect()产生;

  • listening(监听)链接:通过调用mg_bind()产生;

  • inbound(入站)链接:listening链接所收到的链接;

Mongoose应用应遵循事件驱动模式,通过mg_mgr_poll()遍历所有的套接字,接受新链接、发送、接收数据、关闭链接;并为各自的事件调用事件处理函数。

 
  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_pool()创建事件循环      mg_mgr_poll(&mgr, 1000);   }
 
 

缓冲区

每个连接都有一个发送和接收缓冲区:

  • mg_connection::send_mbuf
    :将接收到的数据加到recv_mbuf
    后面,并触发一个MG_EV_RECV
    事件;

  • mg_connection::recv_mbuf
    :用户发送数据(mg_send()
    或 mg_printf()
    )时,输出函数将数据追加到send_mbuf
    ;成功地将数据写到socket后,丢弃缓冲区中的数据并触发一个MG_EV_SEND
    事件;

连接关闭后,触发一个MG_EV_CLOSE
事件。

事件处理函数

每个链接都有其与之相关的事件处理函数,是数据处理的关键元素。

 
  static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {     switch (ev) {       /* Event handler code that defines behavior of the connection */       ...     }   }
 
 

参数说明:

  • mg_connection *nc
    :触发事件的连接;内部有void *user_data
    字段,可保存用户自定义信息;

  • int ev
    :事件编号;

  • void *ev_data
    : 事件数据指针(不同的事件有不同的意义)

事件

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

核心事件说明:

  • MG_EV_ACCEPT
    : 接收到新连接,void *ev_data
    是远程端的union socket_address

  • MG_EV_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()
    丢弃已处理的数据(用户有责任从接收缓冲区丢弃已处理的数据)。

  • MG_EV_SEND
    : 已将数据写入到socket中,并且已经丢弃写入到mg_connection::send_mbuf
    的数据;void *ev_data
    int *num_sent_bytes

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

  • MG_EV_TIMER
    : 当mg_set_timer()
    调用后触发。

连接flags

每个链接都有flags位域。

由事件处理程序设置的链接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_USER_1,MG_USER_2,MG_USER_3,MG_USER_4:开发者可用它来存储特定应用程序的状态

由mongoose设置的flags:

  • MG_F_SSL_HANDSHAKE_DONE:ssl握手完成时设置;

  • MG_F_CONNECTING:在mg_connect()调用后链接处于链接状态,但未完成链接时设置;

  • MG_F_LISTENING:在监听中;

  • MG_F_UDP:链接是udp时设置;

  • MG_F_WEBSOCKET:链接是websocket时设置;

  • MG_F_WEBSOCKET_NO_DEFRAG:如果用户想关闭websocket的自动帧碎片整理功能,则由用户设置此标记。

Http示例

HTTP请求中主要消息格式为:

 
  struct http_message {       struct mg_str message; /* Whole message: request line + headers + body */       struct mg_str body;    /* Message body. 0-length for requests with no body */           /* HTTP Request line (or HTTP response line) */       struct mg_str method; /* "GET" */       struct mg_str uri;    /* "/foo/bar" */       struct mg_str proto;  /* "HTTP/1.1" -- for both request and response */           /* For responses, code and response status message are set */       int resp_code;       struct mg_str resp_status_msg;           /*        * Query-string part of the URI. For example, for HTTP request        *    GET /foo/bar?param1=val1&param2=val2        *       |   uri  |     query_string     |        *        * Note that question mark character doesn't belong neither to the uri,        * nor to the query_string        */       struct mg_str query_string;           /* Headers:默认最多40个,可根据需要修改 */       struct mg_str header_names[MG_MAX_HTTP_HEADERS];       struct mg_str header_values[MG_MAX_HTTP_HEADERS];   };    
 
 

RESTful Server

对于Http请求,MG_EV_HTTP_MSG为接收到消息时触发的事件。

mg_http_message中存放的是Http请求的消息,通过mg_http_reply来应答Http请求。

 
  std::string getMgStr(struct mg_str str) {       return std::string(str.ptr, str.len);   }       // We use the same event handler function for HTTP and HTTPS connections   // fn_data is NULL for plain HTTP, and non-NULL for HTTPS   static void funCallback(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {       std::cout << "Connect from: " << c->peer.ip << ":" << c->peer.port << ", type: " << ev << std::endl;           if (ev == MG_EV_ACCEPT && fn_data != NULL) {           struct mg_tls_opts opts = {                   //.ca = "ca.pem",         // Uncomment to enable two-way SSL                   .cert = "server.pem",    // Certificate PEM file                   .certkey = "server.pem", // This pem contains both cert and key           };           mg_tls_init(c, &opts);       } else if (ev == MG_EV_HTTP_MSG) {           struct mg_http_message *hm = (struct mg_http_message *) ev_data;               std::cout << "Http request: Method=" << getMgStr(hm->method) << ", URI=" << getMgStr(hm->uri)                     << ", query=" << getMgStr(hm->query) << ", proto=" << getMgStr(hm->proto) << std::endl;           std::cout << "Request body: " << getMgStr(hm->body) << std::endl;           if (mg_vcmp(&hm->uri, "/api/f1") == 0) {// Serve REST               json jData = json::parse(hm->body.ptr, hm->body.ptr + hm->body.len);               std::cout << "##iterate data\n";               for (auto it:jData) {                   std::cout << "value: " << it << '\n';               }               std::cout << "##iterate items\n";               for (auto &el:jData.items()) {                   std::cout << "Key: " << el.key() << ", value: " << el.value() << '\n';               }               mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123);           } else if (mg_http_match_uri(hm, "/api/f2/*")) {               mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int) hm->uri.len, hm->uri.ptr);           } else {               // struct mg_http_serve_opts opts = {.root_dir = s_root_dir};               // mg_http_serve_dir(c, ev_data, &opts);                   mg_http_reply(c, 200, "", "Unknown request\n"); // Serve REST           }       }       (void) fn_data;   }       void startHttpServer() {       struct mg_mgr mgr;       // Event manager       mg_log_set("2");         // Set to 3 to enable debug       mg_mgr_init(&mgr);       // Initialise event manager       mg_http_listen(&mgr, s_http_addr, funCallback, NULL);   // Create HTTP listener   //    mg_http_listen(&mgr, s_https_addr, funCallback, (void *) 1); // HTTPS listener       for (;;)           mg_mgr_poll(&mgr, 1000); // Infinite event loop       mg_mgr_free(&mgr);   }
 
 

 

HTTP实例:HTTP server

        1,使用mg_bind()或者mg_bind_opt()创建立监听链接

        2.调用mg_set_protocol_http_websocket()去监听所有链接。此函数附加了一个内置的http事件处理事件,用于解析并触发特定的HTTP事件。例如当HTTP请求被完全缓冲时,内置的HTTP处理程序将解析请求并使用MG_EV_HTTP_REQUEST事件调用用户定义的事件处理函数,并将HTTP请求解析为事件数据。

        3.创建事件处理函数。事件处理程序接收所有的事件(低级别TCP事件(MG_EV_RECV)和高级别HTTP事件(MG_EV_HTTP_REQUEST))。通常事件处理函数应该只处理高级别事件MG_EV_HTTP_REQUEST

    下面是HTTP server的实例代码,其中省略了错误检查

 
  // Copyright (c) 2015 Cesanta Software Limited   // All rights reserved       #include "mongoose.h"       static const char *s_http_port = "8000";   static struct mg_serve_http_opts s_http_server_opts;       static void ev_handler(struct mg_connection *nc, int ev, void *p) {     if (ev == MG_EV_HTTP_REQUEST) {       mg_serve_http(nc, (struct http_message *) p, s_http_server_opts);     }   }       int main(void) {     struct mg_mgr mgr;     struct mg_connection *nc;         mg_mgr_init(&mgr, NULL);     printf("Starting web server on port %s\n", s_http_port);     nc = mg_bind(&mgr, s_http_port, ev_handler);     if (nc == NULL) {       printf("Failed to create listener\n");       return 1;     }         // Set up HTTP server parameters     mg_set_protocol_http_websocket(nc);     s_http_server_opts.document_root = ".";  // Serve current directory     s_http_server_opts.enable_directory_listing = "yes";         for (;;) {       mg_mgr_poll(&mgr, 1000);     }     mg_mgr_free(&mgr);         return 0;   }
 
 

使能SSL(HTTPS)


    在http服务器端使能ssl需要按照如下步骤:

        1.获取ssl证书和私钥文件

        2.声明struct mg_bind_opts,初始化化ssl_cert和ssl_key

        3.使用mg_bind_opt()去创建监听socket

实例:(更多介绍:查看examples中的https server 实例)

 
  int main(void) {     struct mg_mgr mgr;     struct mg_connection *c;     struct mg_bind_opts bind_opts;         mg_mgr_init(&mgr, NULL);         memset(&bind_opts, 0, sizeof(bind_opts));     bind_opts.ssl_cert = "server.pem";     bind_opts.ssl_key = "key.pem";         // Use bind_opts to specify SSL certificate & key file     c = mg_bind_opt(&mgr, "443", ev_handler, bind_opts);     mg_set_protocol_http_websocket(c);         ...   }
 
 

标签:MG,HTTP,struct,mg,网络,mgr,mongoose,EV
From: https://www.cnblogs.com/lidabo/p/17216814.html

相关文章

  • tcp网络编程实例1
    tcp_server.c#include<signal.h>#include<stdio.h>#include<errno.h>#include<unistd.h>#include<stdlib.h>#include<time.h>#include<string.h>#include......
  • Linux网络服务:DNS域名服务系统
    DNS域名系统服务1.DNS介绍1.1什么是域名?域名(DomainName),简称域名、网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计......
  • Linux网络服务:DHCP
    网络服务-DHCP1.DHCP简介 DHCP(DynamicHostConfigurationProtocol,动态主机配置协议)是一个工作在应用层的局域网网络协议,数据传输时使用UDP不可靠传输协议工作,通常被应......
  • 转:卷积神经网络
    自今年七月份以来,一直在实验室负责卷积神经网络(ConvolutionalNeuralNetwork,CNN),期间配置和使用过theano和cuda-convnet、cuda-convnet2。为了增进CNN的理解和使用,特写此博......
  • TCPIP网络编程 -- (四)基于 TCP 的服务端客户端(1)
    TCP/IP网络编程--(四)基于TCP的服务端/客户端(1)4.2实现基于CP的服务器端/客户端等待连接请求阶段#include<sys/socket.h>intlisten(intsock,intbacklog);......
  • TCPIP网络编程 -- (五)基于 TCP 的服务端客户端(2)
    TCP/IP网络编程--(五)基于TCP的服务端/客户端(2)5.1回声服务器的完美实现由于上一章末尾提到的问题write(sock,message,strlen(message));str_len=read(sock,mess......
  • 基于交换机、智能网卡、光模块的400G数据中心网络解决方案
    400G数据中心网络市场发展迅猛,更大吞吐量的交换芯片、更高速率的光连接件、爆炸式的数据增长,在合力加速数据中心网络的发展。除此之外,随着5G的蓬勃发展和基于视频的数据传输......
  • 网络分析工具:nc/tcpdump/wireshark
     ncLinuxnc命令用于设置路由器nc[-hlnruz][-g<网关...>][-G<指向器数目>][-i<延迟秒数>][-o<输出文件>][-p<通信端口>][-s<来源位址>][-v...][-w<超时秒数>][主机名称......
  • 易语言 爬虫 网络请求 保存图片
    1网页_访问_对象介绍详细参考:http://e.125.la/fun-1161.html本教程基于精易模块​​​网页_访问_对象​​属性2参数介绍参数名类型备注网址文本型完整的网页地址,必须包......
  • 网络社群发现算法挖掘bilibili视频流量数据可视化|附代码数据
    原文链接:https://tecdat.cn/?p=19006最近我们被客户要求撰写关于bilibili视频流量数据的研究报告,包括一些图形和统计输出。最新研究表明,中国有超过7亿人在观看在线视频内......