mongoose源码解读(二) -- mg_mgr_init 初始化

        在用 mongoose 源码开发的时候,这个初始化函数 mg_mgr_init()则是必须的,我们看下它到底做了哪些初始化操作。

void mg_mgr_init(struct mg_mgr *m, void *user_data) {struct mg_mgr_init_opts opts;memset(&opts, 0, sizeof(opts));mg_mgr_init_opt(m, user_data, opts);
}

我们是这样调用的 mg_mgr_init(&mgr, nullptr); 所以 user_data 指针为 nullptr, 所以mg_mgr_init_opt() 里后两个参数是都是空的。

用户数据指针赋给了入参 m->user_data,接下来就是 interface 相关的赋值了,因为 m->ifaces 是二级指针,所以给它申请了内存:

 

 这里用到了一个全局变量 mg_ifaces,它的定义是这样的

const struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable,
};

而这个 mg_default_iface_vtable 就是函数指针的集合,

#define MG_SOCKET_IFACE_VTABLE                                          \{                                                                     \mg_socket_if_init,                                                  \mg_socket_if_free,                                                  \mg_socket_if_add_conn,                                              \mg_socket_if_remove_conn,                                           \mg_socket_if_poll,                                                  \mg_socket_if_listen_tcp,                                            \mg_socket_if_listen_udp,                                            \mg_socket_if_connect_tcp,                                           \mg_socket_if_connect_udp,                                           \mg_socket_if_tcp_send,                                              \mg_socket_if_udp_send,                                              \mg_socket_if_tcp_recv,                                              \mg_socket_if_udp_recv,                                              \mg_socket_if_create_conn,                                           \mg_socket_if_destroy_conn,                                          \mg_socket_if_sock_set,                                              \mg_socket_if_get_conn_addr,                                         \}#if MG_NET_IF == MG_NET_IF_SOCKET
const struct mg_iface_vtable mg_default_iface_vtable = MG_SOCKET_IFACE_VTABLE;
#endif

这些函数指针集合就是对应这个包含了函数指针定义的结构体:

struct mg_iface_vtable {void (*init)(struct mg_iface *iface);void (*free)(struct mg_iface *iface);void (*add_conn)(struct mg_connection *nc);void (*remove_conn)(struct mg_connection *nc);time_t (*poll)(struct mg_iface *iface, int timeout_ms);/* Set up a listening TCP socket on a given address. rv = 0 -> ok. */int (*listen_tcp)(struct mg_connection *nc, union socket_address *sa);/* Request that a "listening" UDP socket be created. */int (*listen_udp)(struct mg_connection *nc, union socket_address *sa);/* Request that a TCP connection is made to the specified address. */void (*connect_tcp)(struct mg_connection *nc, const union socket_address *sa);/* Open a UDP socket. Doesn't actually connect anything. */void (*connect_udp)(struct mg_connection *nc);/* Send functions for TCP and UDP. Sent data is copied before return. */int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len);int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len,union socket_address *sa, size_t *sa_len);/* Perform interface-related connection initialization. Return 1 on ok. */int (*create_conn)(struct mg_connection *nc);/* Perform interface-related cleanup on connection before destruction. */void (*destroy_conn)(struct mg_connection *nc);/* Associate a socket to a connection. */void (*sock_set)(struct mg_connection *nc, sock_t sock);/* Put connection's address into *sa, local (remote = 0) or remote. */void (*get_conn_addr)(struct mg_connection *nc, int remote,union socket_address *sa);
};

所以像源码里发送、接收数据的调用都是这样调用的:

nc->iface->vtable->tcp_send

nc->iface->vtable->tcp_recv

那调用的都是上面的函数指针,如果是启用了 ssl 的可能又是另外一套函数指针接口了。

其实我们还可以从 GDB 里看到:

active_connections 保存的就是 struct mg_connection *con = mg_bind(&mgr, buf, nullptr); 这个con:

 

 然后看mgr 里的 ifaces 是二级指针,看一下它的值:

二级指针,解引用两次得到它里面的内容,而这个 vtable 又是一个指针,它指向了 mg_default_iface_vtable,这个就是函数指针接口的集合了:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/709838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode : 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 思路:遍历数组元素,判定为0,则采用erase从数组删除&…

算法修炼-动态规划之斐波那契数列模型

一、动态规划的算法原理 这是本人动态规划的第一篇文章,所以先阐述一下动态规划的算法原理以及做题步骤。动态规划本人的理解就是通过题目所给的条件正确地填满dp表(一段数组)。首先要先确定好dp表每个位置的值所代表的含义是什么&#xff0c…

JavaEE——简单认识JavaScript

文章目录 一、简单认识 JavaScript 的组成二、基本的输入输出和简单语法三、变量的使用四、JS 中的动态类型图示解释常见语言的类型形式 五、JS中的数组六、JS 中的函数七、JS 中的对象 一、简单认识 JavaScript 的组成 对于 JavaScript ,其中的组成大致分为下面的…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的水果质量识别系统(Python+PySide6界面+训练代码)

摘要:本篇博客详尽介绍了一套基于深度学习的水果质量识别系统及其实现代码。系统采用了尖端的YOLOv8算法,并与YOLOv7、YOLOv6、YOLOv5等前代算法进行了详细的性能对比分析,提供在识别图像、视频、实时视频流和批量文件中水果方面的高效准确性…

【探索AI】探索未来-计算机专业必看的几部电影

计算机专业必看的几部电影 计算机专业必看的几部电影,就像一场精彩的编程盛宴!《黑客帝国》让你穿越虚拟世界,感受高科技的魅力;《社交网络》揭示了互联网巨头的创业之路,《源代码》带你穿越时间解救世界,…

【Java程序设计】【C00327】基于Springboot的高校教师教研信息填报系统(有论文)

基于Springboot的高校教师教研信息填报系统(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的高校教师教研信息填报系统,本系统有管理员、教研管理以及教研人员三种角色; 管理员&#xff1a…

行为树入门:BehaviorTree.CPP Groot2练习(叶子节点)(2)

以《行为树BehaviorTree学习记录1_基本概念》练习。 1 SequenceNode顺序控制节点 代码下载 git clone https://gitee.com/Luweizhiyuan2020/ros2_bt.git例程 1.1 sequence 顺序执行 下载版本SequenceNode1。 1.2 ReactiveSequence 异步执行 注意: ①only a…

打造透明银行存储:Solidity智能合约的实践与探索

引言: 随着区块链技术的快速发展,智能合约作为其中的核心组件,正被越来越多地应用于各种场景。作为智能合约的编程语言,Solidity因其对以太坊平台的深度支持而备受关注。在这篇文章中,我们将通过构建一个透明的银行存储…

shell自定义日志输出函数log

Background 在编写比较复杂的脚本时,需要输出相关日志信息,方便知悉脚本的执行情况以及问题的排查。 源码 log.sh # 自定义日志函数 function log(){if [[ $1 "i" || $1 "info" ]]; thenecho -ne "\033[1;34mINFO: \033[0m&…

如何将字体添加到 ONLYOFFICE 桌面编辑器8.0

作者:VincentYoung 为你写好的文字挑选一款好看的字体然而自带的字体列表却找不到你喜欢的怎么办?这只需要自己手动安装一款字体即可。这里教你在不同的桌面操作系统里的多种字体安装方法。 ONLYOFFICE 桌面编辑器 ONLYOFFICE 桌面编辑器是一款免费的办…

《互联网的世界》第三讲-tcp

dns 找到了地址,spf 确定了路径,如何运输数据呢?今天讲 tcp。 计算机网络领域的特定技术是最后当你干这个事时才要用的,我对孩子们这样说,实际上你可以随便看一个快递单子来理解端到端传输协议。 源地址&#xff0c…

qtcreator-ros 安装记录

文章目录 ros_qtc_pluginros_qt_demo参考链接ros_qtc_plugin ROS Qt Creator 插件是专门为 ROS 开发的,通过简化任务和为 ROS 工具创建集中位置来提高开发人员的效率。由于它建立在Qt Creator平台之上,用户可以访问其所有现有功能,例如:语法高亮,代码索引,编辑器(C++,…

[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式

前言: 为什么之前写过Golang 版的设计模式,还在重新写Java 版? 答:因为对于我而言,当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言,更适合用于学习设计模式。 为什么类图要附上uml 因为很…

【Intel oneAPI实战】使用英特尔套件解决杂草-农作物检测分类的视觉问题

目录 一、简介:计算机视觉挑战——检测并清除杂草二、基于YOLO的杂草-农作物检测分类2.1、YOLO简介2.2、基于YOLO的杂草-农作物检测分类解决方案 三、基于YOLO的杂草-农作物检测分类系统设计3.1、基于flask框架的demo应用程序后端3.2、基于Vue框架的demo应用程序前端…

Python的报错类型

在编写python代码时,当不当使用时,python会给出错误提示,常见的错误类型有如下几种: 1.TpyeError类型错误 ① 传入的参数数量不对:如调abs()有且仅有1个参数,但给出了两个时,python会给出提示…

yolov9,使用自定义的数据训练推理

[源码 🐋]( GitHub - WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information) [论文 📘](arxiv.org/pdf/2402.13616.pdf) 论文摘要:本文介绍了一种新的目标检测…

网络防御保护3

一、双击热备 1,根据网段划分配置IP地址和安全区域 2,配置双机热备场景 主备场景配置 抢占延时仅对主设备生效。 hello报文周期时间--- 默认为1S,可以修改,但是,主备设备需要同时修改为相同值。 同步配置 双机热备的…

【C++】手把手教你手搓模拟实现string类

前言 string类一直都是C的经典问题,之前的文章已经对string类做了一个基本的介绍(string类的基本常用接口),为了更好理解string类的功能,此篇文章将手把手教你带你手搓模拟实现string类,快来一起学习吧&am…

预训练大模型LLM的PEFT之—— Prefix Tuning

简介 Prefix Tuning是2021.01提出来的,在它之前,我们使用prompt主要是人工设计模板或者自动化搜索模板,也就是prompt范式的第一阶段,就是在输入上加上prompt文本,再对输出进行映射。这种离散模板对模型的鲁棒性很差。…

SpringBoot接收参数的几种形式

SpringBoot接收参数的几种形式 在SpringBoot中获取参数基本方式有5种,需要都掌握. 这里需要记住一个技术术语或概念 API接口: 你写好的那个URL地址,就被称为API接口 1. 接收常规参数 给/param/demo1这个URL接口发送id, name两个参数 以上是以GET请求类型进行发送,实际发送…