当前位置: 首页 > news >正文

lwIP 细节之六:connected、sent、poll 回调函数是何时调用的

使用 lwIP 协议栈进行 TCP 裸机编程,其本质就是编写协议栈指定的各种回调函数。将你的应用逻辑封装成函数,注册到协议栈,在适当的时候,由协议栈自动调用,所以称为回调

注:除非特别说明,以下内容针对 lwIP 2.0.0 及以上版本。

向协议栈注册回调函数有专门的接口,如下所示:

tcp_err(pcb, errf);							//注册 TCP 接到 RST 标志或发生错误回调函数 errf
tcp_connect(pcb, ipaddr, port, connected);	//注册 TCP 建立连接成功回调函数 connecter
tcp_accept(pcb, accept);					//注册 TCP 处于 LISTEN 状态时,监听到有新的连接接入
tcp_recv(pcb, recv);						//注册 TCP 接收到数据回调函数 recv
tcp_sent(pcb, sent);						//注册 TCP 发送数据成功回调函数 sent
tcp_poll(pcb, poll, interval);				//注册 TCP 周期性执行回调函数 poll

本节讲述 connectedsentpoll 回调函数。

connected 回调函数

在 TCP 控制块中,函数指针 connected 指向用户实现的函数,当一个 PCB 连接到远端主机时,由协议栈调用此函数。
函数指针 connected 的类型为 tcp_connected_fn,该类型定义在 tcp.h 中:

/** Function prototype for tcp connected callback functions. Called when a pcb* is connected to the remote side after initiating a connection attempt by* calling tcp_connect().** @param arg Additional argument to pass to the callback function (@see tcp_arg())* @param tpcb The connection pcb which is connected* @param err An unused error code, always ERR_OK currently ;-) @todo!*            Only return ERR_ABRT if you have called tcp_abort from within the*            callback function!** @note When a connection attempt fails, the error callback is currently called!*/
typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);

协议栈通过宏 TCP_EVENT_CONNECTED(pcb,err,ret) 调用 pcb->connected 指向的函数,宏 TCP_EVENT_CONNECTED 定义在 tcp_priv.h 中:

#define TCP_EVENT_CONNECTED(pcb,err,ret)                         \do {                                                           \if((pcb)->connected != NULL)                                 \(ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \else (ret) = ERR_OK;                                         \} while (0)

以关键字 TCP_EVENT_CONNECTED 搜索源码,可以搜索到 1 处使用:

TCP_EVENT_CONNECTED(pcb, ERR_OK, err);

这句代码在 tcp_process 函数中,PCB 控制块处于 SYN_SENT 状态的连接,收到 SYN + ACK 标志且序号正确,则调用宏 TCP_EVENT_CONNECTED 回调 connected 指向的函数,报告应用层连接

static err_t
tcp_process(struct tcp_pcb *pcb)
{/* Do different things depending on the TCP state. */switch (pcb->state) {case SYN_SENT:/* received SYN ACK with expected sequence number? */if ((flags & TCP_ACK) && (flags & TCP_SYN)&& (ackno == pcb->lastack + 1)) {// PCB 字段更新/* Call the user specified function to call when successfully connected. */TCP_EVENT_CONNECTED(pcb, ERR_OK, err);if (err == ERR_ABRT) {return ERR_ABRT;}tcp_ack_now(pcb);}break;}return ERR_OK;
}

sent 回调函数

在 TCP 控制块中,函数指针 sent 指向用户实现的函数,当成功发送数据后,由协议栈调用此函数,通知用户数据已成功发送。
函数指针 sent 的类型为 tcp_sent_fn ,该类型定义在 tcp.h 中:

/** Function prototype for tcp sent callback functions. Called when sent data has* been acknowledged by the remote side. Use it to free corresponding resources.* This also means that the pcb has now space available to send new data.** @param arg Additional argument to pass to the callback function (@see tcp_arg())* @param tpcb The connection pcb for which data has been acknowledged* @param len The amount of bytes acknowledged* @return ERR_OK: try to send some data by calling tcp_output*            Only return ERR_ABRT if you have called tcp_abort from within the*            callback function!*/
typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb,u16_t len);

通过注释可以知道当数据成功发送后(收到远端主机 ACK 应答),调用 sent 回调函数,用于释放某些资源(如果用到的话)。这也意味着 PCB 现在有可以发送新的数据的空间了。
协议栈通过宏 TCP_EVENT_SENT(pcb,space,ret) 调用 pcb->sent 指向的函数。宏 TCP_EVENT_SENT 定义在 tcp_priv.h 中:

#define TCP_EVENT_SENT(pcb,space,ret)                          \do {                                                         \if((pcb)->sent != NULL)                                    \(ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space));  \else (ret) = ERR_OK;                                       \} while (0)

以关键字 TCP_EVENT_SENT 搜索源码,可以搜索到 1 处使用:

TCP_EVENT_SENT(pcb, (u16_t)acked16, err);

这是在 tcp_input 函数中,如果收到数据 ACK 应答,则回调 sent 函数,应答的数据字节数作为参数传到到回调函数。

void
tcp_input(struct pbuf *p, struct netif *inp)
{// 经过一系列检测,没有错误/* 在本地找到有效的控制块 pcb */if (pcb != NULL) {err = tcp_process(pcb);if (err != ERR_ABRT) {if (recv_flags & TF_RESET) {// 收到 RST 标志,回调 errf 函数TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST);tcp_pcb_remove(&tcp_active_pcbs, pcb);tcp_free(pcb);} else {if (recv_acked > 0) {// 收到数据 ACK 应答,回调 sent 函数TCP_EVENT_SENT(pcb, (u16_t)acked16, err);	// <--- 这里if (err == ERR_ABRT) {goto aborted;}recv_acked = 0;}if (recv_data != NULL) {// 收到有效数据, 回调 recv 函数TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);if (err == ERR_ABRT) {goto aborted;}}if (recv_flags & TF_GOT_FIN) {// 收到 FIN 标志,回调 recv 函数,远端关闭连接TCP_EVENT_CLOSED(pcb, err);		if (err == ERR_ABRT) {goto aborted;}}/* Try to send something out. */tcp_output(pcb);}}} 
}

poll 回调函数

在 TCP 控制块中,函数指针 poll 指向用户实现的函数,协议栈周期性的调用此函数,“周期“由用户在注册回调函数时指定,最小为 TCP_SLOW_INTERVAL 毫秒(默认 500),用户层可以使用这个回调函数做一些周期性处理。
函数指针 poll 的类型为 tcp_poll_fn ,该类型定义在 tcp.h 中:

/** Function prototype for tcp poll callback functions. Called periodically as* specified by @see tcp_poll.** @param arg Additional argument to pass to the callback function (@see tcp_arg())* @param tpcb tcp pcb* @return ERR_OK: try to send some data by calling tcp_output*            Only return ERR_ABRT if you have called tcp_abort from within the*            callback function!*/
typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb);

协议栈通过宏 TCP_EVENT_POLL(pcb,ret) 调用 pcb->poll 指向的函数。宏 TCP_EVENT_POLL 定义在 tcp_priv.h 中:

#define TCP_EVENT_POLL(pcb,ret)                                \do {                                                         \if((pcb)->poll != NULL)                                    \(ret) = (pcb)->poll((pcb)->callback_arg,(pcb));          \else (ret) = ERR_OK;                                       \} while (0)

以关键字 TCP_EVENT_POLL 搜索源码,可以搜索到 1 处使用:

TCP_EVENT_POLL(prev, err);

这是在 tcp_slowtmr 函数中,当达到设定的时间时,调用 poll 回调函数。简化后的代码为:

void
tcp_slowtmr(void)
{++prev->polltmr;if (prev->polltmr >= prev->pollinterval) {prev->polltmr = 0;TCP_EVENT_POLL(prev, err);	// <-- 这里/* if err == ERR_ABRT, 'prev' is already deallocated */if (err == ERR_OK) {tcp_output(prev);}}}
}






读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
千金难买知识,但可以买好多奶粉

相关文章:

lwIP 细节之六:connected、sent、poll 回调函数是何时调用的

使用 lwIP 协议栈进行 TCP 裸机编程&#xff0c;其本质就是编写协议栈指定的各种回调函数。将你的应用逻辑封装成函数&#xff0c;注册到协议栈&#xff0c;在适当的时候&#xff0c;由协议栈自动调用&#xff0c;所以称为回调。 注&#xff1a;除非特别说明&#xff0c;以下内…...

C语言搭建项目-学生管理系统(非链表)

、 目录 搭建offer.h文件 搭建offer.c中的main函数 密码登入系统 搭建my_oferr.c中的接口函数 使用帮助菜单接口函数 增加学生信息接口函数 查询学生信息接口函数 删除学生信息接口函数 保存学生信息接口 打开文件fopen 关闭文件fclose 判断是否保存文件fwrite 退出执行文件…...

美易官方:投资美股证券投资组合的优势及快速上手指南

投资美股证券投资组合的优势及快速上手指南 美股证券投资组合的优势 美国股市一直以来都是全球投资者的热门选择之一。与其他市场相比&#xff0c;美国股市具有诸多优势&#xff0c;如市场规模大、流动性好、信息透明度高等。投资者在美国股市中&#xff0c;可以选择各种不同类…...

centos日常运维随记

# 需要生成随机字符及数字 rootAAA:~# echo $RANDOM | md5sum |cut -c 3-29 e7e8942a791146531f613c7c757 # echo $RANDOM 产生随机数据 # md5sum 随机数生成md5值 # cut -c 3-29 :md5产生的是32的md5数&#xff0c;使用cut -c 对这个数进行 第3位到第29位的截取# 在现有的…...

设计模式之观察者模式(主题对象发生变化,通知各个观察者)

当涉及到电商场景时&#xff0c;观察者模式可以用于处理多种情况&#xff0c;比如订单状态更新、库存变化、用户积分变化等。下面是一个简化的订单状态更新的观察者模式案例。 1.首先&#xff0c;定义一个主题接口 OrderSubject /*** Description:主题&#xff0c;用于管理观察…...

vue+高德,百度地图

1&#xff0c;npm安装vue-amap npm install vue-amap --save 2&#xff0c;main.js引入 import VueAMap from vue-amap; Vue.use(VueAMap); VueAMap.initAMapApiLoader({key: ,plugin: [AMap.Autocomplete, AMap.PlaceSearch, AMap.Scale, AMap.OverView, AMap.ToolBar, AMap.…...

工信部举行发布会 数字化产业推动元宇宙发展取得良好成效

据官方消息&#xff0c;工业和信息化部12日举行“发挥国家高新区作用 加快推进新型工业化”新闻发布会。 在数字化建设方面取得了良好的成绩&#xff1a; 一是数字经济加速发展。国家高新区着力推动人工智能、大数据、云计算、区块链和元宇宙等新产业新业态蓬勃发展&#xff…...

有没有手机电脑同步的工作时间管理软件?

越来越多的职场人士感到每天的工作任务是比较多的&#xff0c;而工作时间又是有限的&#xff0c;所以经常时间不够用。因此&#xff0c;对于上班族来说&#xff0c;高效的时间管理是提高工作效率、按时完成任务的关键。为了满足这一需求&#xff0c;很多网友都在寻找一款既能在…...

docker安装及简单使用(Linux版本)

文章目录 前言一、docker安装二、docker命令pull&#xff08;安装镜像&#xff09;rmi&#xff08;删除镜像&#xff09;images&#xff08;查看镜像&#xff09;run&#xff08;创建容器&#xff09;删除容器exec&#xff08;进入运行中的容器&#xff09;常用命令 总结如有启…...

山西电力市场日前价格预测【2023-12-10】

1.日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-12-10&#xff09;山西电力市场全天平均日前电价为384.75元/MWh。其中&#xff0c;最高日前价格为493.66元/MWh&#xff0c;预计出现在16: 00。最低日前电价为282.24元/MWh&#xff0c;预…...

在OpenCV基于深度学习的超分辨率模型实践

1. 引言 OpenCV是一个开源的计算机视觉库&#xff0c;拥有大量优秀的算法。基于最新的合并&#xff0c;OpenCV包含一个易于使用的接口&#xff0c;主要用于实现基于深度学习方法的超分辨率&#xff08;SR&#xff09;。该接口包含预先训练的模型&#xff0c;这些模型可以非常容…...

beebox靶场A3 中等级别 xss通关教程

特别注意&#xff0c;低级和中级的差别在于中级使用了一些函数进行了过滤或转义字符 例如 addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。 预定义字符是&#xff1a; 单引号&#xff08;&#xff09;双引号&#xff08;"&#xff09;反斜杠&#xff08;\&…...

前端知识笔记(二)———Django与Ajax

特点&#xff1a; 异步提交 局部刷新 例子&#xff1a;github注册 动态获取用户名实时的跟后端确认并实时的展示到前端&#xff08;局部刷新&#xff09; 朝后端发送请求的方式 1.浏览器地址栏直接输入url回车 -----》get请求 2.a标签的href属性 -----》get请求 3…...

C++新经典模板与泛型编程:用成员函数重载实现is_base_of

用成员函数重载实现is_base_of std::is_base_of是一个C 11标准中用于判断某个类是否是另一个类父类的类模板。 #include "killCmake.h"#include<string>using namespace std;class A { };class B : public A { public:B(int x): x_(x){} private:int x_; };/…...

【vue3】处理数组方法,在数组中获取指定条件所在的数组对象等持续更新笔记~~

1、在数组中获取指定条件所在的数组对象 &#xff08;1&#xff09;filter方法获取到的是包含指定项的数组 data.checkRow res.result.filter(item > item.checked 1);打印&#xff1a; &#xff08;2&#xff09;map方法取到的是包含指定项的数组&#xff0c;如果满足…...

digit函数

题目描述 在程序中定义一函数 digit(n,k)&#xff0c;它能分离出整数 n 从右边数第 k 个数字。 输入格式 正整数 n 和 k。 输出格式 一个数字。 输入输出样例 输入 #1 31859 3 输出 #1 8 说明/提示 n≤10^9。 k≤10。 因为用整数n来做有点难&#xff0c;所以我用…...

Linux中的堡垒机搭建以及使用

JumpServer搭建 安装应用包 curl -sSL https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash 一路回车即可安装完毕&#xff08;可根据需求更改&#xff09; JumpServer的 配置文件路径 /opt/jumpserver/config/config.tx…...

ubuntu安装微信客户端

安装 Wine 环境 Wine环境包下载地址&#xff1a;http://archive.ubuntukylin.com/software/pool/partner/ukylin-wine_70.6.3.25_amd64.deb 下载完安装包后在命令行运行以下命令安装环境&#xff1a; sudo apt-get install -f -y ./ukylin-wine_70.6.3.25_amd64.deb 安装微信…...

ajax清空所有表单内容,包括input标签、单选框radio、多选框CheckBox、下拉框select以及文本域内容

为了实现重置并清空表单内容&#xff0c;你可以使用 jQuery 的 val 方法将各种表单元素的值设置为空字符串&#xff0c;并通过 layui 的 form.render 方法来更新表单的渲染。以下是修改后的代码&#xff1a; layui.use(["form", "laydate", "jquery&…...

通配符用法

在本篇文章中&#xff0c;本文将说明通配符用法。 &#xff08;1&#xff09;概述 通配符是在Linux命令中用于匹配文件名的特殊字符。它们可以帮助我们快速定位和操作文件。本文将介绍一些常用的通配符及其示例用法。 通配符是一种用于模式匹配的特殊字符。在计算机领域中&am…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...