文章目录

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

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

Mongoose库

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

  • 普通TCP、普通UDP、SSL/TLS(单向或双向)、客户端和服务器。
  • http客户端和服务器。
  • WebSocket客户端和服务器。
  • MQTT客户机和服务器。
  • CoAP客户端和服务器。
  • DNS客户端和服务器。
  • 异步DNS解析程序。

设计理念

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::recv_mbuf:将接收到的数据加到recv_mbuf后面,并触发一个MG_EV_RECV事件;
  • mg_connection::send_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_dataint *success;当success是0,则连接已经建立,否则包含一个错误码(mg_connect_opt()函数来查看错误码)。
  • MG_EV_RECV:接收数据并追加到recv_mbuf时触发。void *ev_dataint *num_received_bytes(接收到的数据长度)。通常,事件处理函数应通过nc->recv_mbuf检查接收数据,并通过mbuf_remove()丢弃已处理的数据(用户有责任从接收缓冲区丢弃已处理的数据)。
  • MG_EV_SEND: 已将数据写入到socket中,并且已经丢弃写入到mg_connection::send_mbuf的数据;void *ev_dataint *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 RESTjson 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 managermg_log_set("2");         // Set to 3 to enable debugmg_mgr_init(&mgr);       // Initialise event managermg_http_listen(&mgr, s_http_addr, funCallback, NULL);   // Create HTTP listener
//    mg_http_listen(&mgr, s_https_addr, funCallback, (void *) 1); // HTTPS listenerfor (;;)mg_mgr_poll(&mgr, 1000); // Infinite event loopmg_mgr_free(&mgr);
}

[C++]-网络库mongoose简介相关推荐

  1. muduo网络库:18---muduo简介之(muduo库的由来、编译安装、目录结构、代码结构、线程模型)

    一.由来 2010年3月陈硕先生写了一篇<学之者生,用之者死--ACE历史与简评>(文章参阅:https://blog.csdn.net/Solstice/article/details/ ...

  2. 网络增强现实开发简介 Introduction to Web AR development

    搭配webXR.mindAR.three.js和tensorflow.js 你会学到: 获得构建不同类型的网络增强现实应用程序的实践经验,包括图像效果.人脸效果和世界效果 获得关于增强现实如何在网络浏 ...

  3. Py之tornado:tornado库的简介、安装、使用方法之详细攻略

    Py之tornado:tornado库的简介.安装.使用方法之详细攻略 目录 tornado库的简介 tornado库的安装 tornado库的使用方法 1.简单的Tornado的"Hell ...

  4. Py之face_alignment:face_alignment库的简介、安装、使用方法之详细攻略

    Py之face_alignment:face_alignment库的简介.安装.使用方法之详细攻略 目录 face_alignment库的简介 1.指定在CPU / GPU上运行 2.使用特定的面部检 ...

  5. Py之scikit-learn:机器学习Sklearn库的简介、安装、使用方法(ML算法如何选择)、代码实现之详细攻略

    Py之scikit-learn:机器学习Sklearn库的简介.安装.使用方法.代码实现之详细攻略 目录 scikit-learn的简介 scikit-learn的安装 scikit-learn的使用 ...

  6. Py之dlib:Python库之dlib库的简介、安装、使用方法详细攻略

    Py之dlib:Python库之dlib库的简介.安装.使用方法详细攻略 目录 dlib库的简介 dlib库的安装 dlib库的使用函数 0.利用dlib.get_frontal_face_detec ...

  7. 技术实践 | 聊聊网易云信的信令网络库实践

    导读:信令作为实时音视频技术架构中的重要一环,是对建立实时音视频通信起到关键桥梁性的作用. 文|丁永锋 网易云信资深客户端开发工程师 本文将从信令的概念着手,分享在网易云信新一代音视频技术架构下,信令 ...

  8. XMNetworking 网络库的设计与使用

    2019独角兽企业重金招聘Python工程师标准>>> XMNetwoking 是我们团队开源的一个网络库,详见:GitHub XMNetworking 是一个轻量的.简单易用但功能 ...

  9. Py之scikit-learn:机器学习sklearn库的简介、六大基本功能介绍(数据预处理/数据降维/模型选择/分类/回归/聚类)、安装、使用方法(实际问题中如何选择最合适的机器学习算法)之详细攻略

    Py之scikit-learn:机器学习sklearn库的简介(组件/版本迭代).六大基本功能介绍(数据预处理/数据降维/模型选择/分类/回归/聚类).安装.使用方法(实际问题中如何选择最合适的机器学 ...

最新文章

  1. Android之组件化开发
  2. 【Win 10 应用开发】Toast通知激活应用——前台后台
  3. 大数据hadoop资源网址
  4. python开发stm32软件_ADB+Python+STM32 实现 微信跳一跳辅助
  5. 公务员计算机考试题库,公务员考试题库
  6. VBA调用DOS程序两种方法
  7. Java学习笔记2.3.2 运算符与表达式 - 赋值运算符
  8. Linux内核开发之异步通知与异步I/O《来自linux设备开发详解》
  9. python阅读wtfbook疑问和验证
  10. UnityShader14.1:透明效果实现(下)
  11. [51]12864液晶程序
  12. java向上取整和向下取整,万字长文!
  13. 25 个你可能不知道的 Linux 真相
  14. B站banner图片随鼠标移动虚化效果摸索
  15. 房价会象汽车电脑一样下降
  16. 利用OneDrive网盘建站
  17. 短视频app搭建的技术难点是什么?
  18. char、int、long它们各占几个字节?占几位?
  19. 基于树莓派4b的ubuntu20.04mate配合思岚科技A1激光雷达读取数据,建图、保存和基于arduino的下位机控制
  20. 《DensePose: Dense Human Pose Estimation In The Wild》阅读笔记

热门文章

  1. 曾国藩致沅弟(咸丰八年三月三十日)-以“平和”养德保身
  2. 面试官:Redis 如何实现每周热评功能?说说思路!
  3. 广度优先算法和深度优先算法-树形结构(层级结构)-Java
  4. 编译技术:正规式、NFA、DFA、最简DFA的转换
  5. 国际刑警组织进军元宇宙/ 苹果首席产品设计师离职/ 俄罗斯版“星链”来了…今日更多新鲜事在此...
  6. 传统手机ODM厂商加快布局TWS代工 未来5年可期
  7. ganglia离线安装_Ganglia 监控实战!
  8. c语言8155与单片机,MCS_51单片机与8155H的接口设计
  9. sklearn 引用问题
  10. java中父子类同名变量