【LwIP源码学习3】TCP协议栈分析——数据接收流程

news2024/10/17 11:31:39

前言

本文介绍代码在lwip的tcp_in.c文件中,主要介绍TCP协议栈中数据的接收流程。

正文

1、一个正常的TCP数据,首先会传入到

tcp_input(struct pbuf *p, struct netif *inp)

函数,其中指针p指向传入的数据流。

2、从数据流中获取TCP头部

tcphdr = (struct tcp_hdr *)p->payload;

TCP头部数据结构为:
在这里插入图片描述
3、获取TCP头部中重要信息:

  tcphdr->src = lwip_ntohs(tcphdr->src);
  tcphdr->dest = lwip_ntohs(tcphdr->dest);
  seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno);
  ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno);
  tcphdr->wnd = lwip_ntohs(tcphdr->wnd);

  flags = TCPH_FLAGS(tcphdr);

seqno是序号,是发送方告诉接受方正在发送的报文段的序号。
ackno是确认号,是接收方告诉发送方已经接受到的最后一个报文段序号。
flags是6个控制位,其中的SYN与ACK在3次握手时使用如下:
在这里插入图片描述
客户端发起请求时,SYN为1,ACK为0。
服务器回复时,SYN为1,ACK为1。
客户端再次回复时,SYN为0,ACK为1。
ACK为0时,确认号无效(也就是ackno),建立连接后所有报文ACK置1。

flags中的FIN控制位置1,表示报文段的发送方数据已发送完毕,并要求释放运输连接。
释放TCP连接过程如下:
在这里插入图片描述

4、从 tcp_active_pcbs链表中寻找对应的pcb,寻找方式主要是看端口号和IP号是否能对应上:

if (pcb->remote_port == tcphdr->src &&
        pcb->local_port == tcphdr->dest &&
        ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) &&
        ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr()))

tcp_active_pcbs链表上的pcb都是正在等待接受数据或者发送数据的。

5、将输入数据流放到输入报文段里:

inseg.next = NULL;
inseg.len = p->tot_len;
inseg.p = p;
inseg.tcphdr = tcphdr;

因为lwip每次只处理一个输入数据流,所以输入报文段inseg是一个全局变量,同时也不会出现访问冲突。
报文段的管理如下:
在这里插入图片描述
tcp_active_pcbs链表上有很多活跃pcb,每个pcb有一个unsent指针和一个unacked指针,用于维护TCP协议中的发送窗口,unsent指向发送窗口中还未发送的报文段,unacked指向发送窗口中已经发送但是还没收到响应确认号的报文段。
发送窗口如下:
在这里插入图片描述

6、然后执行:

err = tcp_process(pcb);

进行TCP状态机处理。
TCP状态机转换过程如下:
在这里插入图片描述

7、一个已经建立连接的正常通信的pcb状态是ESTABLISHED
处理代码为:

case ESTABLISHED:
      tcp_receive(pcb);
      if (recv_flags & TF_GOT_FIN) { /* passive close */
        tcp_ack_now(pcb);
        pcb->state = CLOSE_WAIT;
      }
      break;

可以看到是调用tcp_receive()函数对输入数据做进一步处理。这时输入数据仍然在inseg输入报文段这个全局变量里。

8、接下来进入到tcp_receive()函数,首先根据新发送来TCP报文段中的窗口大小更新本pcb的发送窗口大小。

pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd);

9、查看接收到的报文段中显示的报文序号是否在接收窗口内:

if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
                        pcb->rcv_nxt + pcb->rcv_wnd - 1)) 

pcb->rcv_nxt表示下一个要接收的报文序号。
pcb->rcv_wnd表示接收窗口大小。
其中pcb在初始化时,设置接收窗口大小代码如下:

pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND);

在lwipopts.h文件中设置

#define TCP_WND                         (2*TCP_MSS)
#define TCP_MSS                         (1500 - 40) 

也就是窗口大小为两个报文段。

10、查看接收到的报文段序号是否就是期望的序号:

      if (pcb->rcv_nxt == seqno) 

如果是则更新期望报文段序号:

pcb->rcv_nxt = seqno + tcplen;

把收到的数据放到全局变量recv_data里:

recv_data = inseg.p;

11、然后回到tcp_input()函数
首先判断是否接受到了数据:

if (recv_data != NULL)

有数据的话将数据传给应用层:

TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);

然后再试试能不能发点数据出去:

tcp_output(pcb);

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

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

相关文章

mysql的一点理解

1、mysql B树 B树非叶子结点中的key存储的是页的用户记录中最小/最大的主键值,之前不知道非叶子结点中的key存的是最小/最大,以为随便存的一个。 2、mysql范围查询 如果对多个列都进行范围查询,只有对索引最左边的那个列索引才生效。 比如…

字符串和字符数组

1.字符串和\0 c语言中有字符类型,但没有字符串类型,c语言中字符串就是由双引号引起来的一串字符,比如:“abcdef” 字符串常量在末尾隐藏了一个’\0’的转义字符,\0’是作为字符串的结束标志存在的 库函数printf与str…

隔离器“芯”实力,华普微荣获“2024年度硬核信号链芯片奖”

10月14日,由深圳市芯师爷科技有限公司和慕尼黑华南电子展携手主办,深圳市半导体行业协会支持的“第六届硬核芯生态大会暨颁奖典礼”,已于深圳国际会展中心(宝安新馆)成功举办。值此盛会之际,华普微受邀参会…

热成像人像算法呈现方式!

一、热红外成像技术 热红外成像技术利用物体发出的红外辐射进行成像,这种辐射与物体的温度有关。因此,热红外成像可以不受光照条件的影响,且在图像中,人体由于温度较高,通常会比背景显得更亮。 二、图像处理算法 阈…

Python爬虫必备的8大技巧,学习爬虫技巧必看!

想要快速学习爬虫,最值得学习的语言一定是Python,Python应用场景比较多,比如:Web快速开发、爬虫、自动化运维等等,可以做简单网站、自动发帖脚本、收发邮件脚本、简单验证码识别脚本。 爬虫在开发过程中也有很多复用的…

如何有效进行主机加固?深信达MCK提供答案

在数字化时代,企业面临的网络安全威胁日益严峻,尤其是勒索病毒等恶意软件的攻击,给企业带来了巨大的挑战。为了有效应对这些威胁,企业需要采取全面的网络安全防护措施,其中主机加固成为了关键的一环。深信达的MCK主机加…

【Arthas】【持续更新】三分钟掌握arthas常用查询命令,入门到实战

Arthas 一、下载和启动1、官网地址2、下载3、启动4、退出 二、常用命令1、dashboard:当前系统的实时数据面板2、profiler:监控进程的cpu\内存使用情况。细致到某个方法采集与生成报告查看 profiling 状态查看 profiler 自身的内存占用 3、thread&#xf…

GPT4o,GPTo1-preview, 拼

兄弟们GPT刚开的 需要上车的扣,工作用 大家一起PIN分摊点压力。 在当今数字化的时代,程序员这一职业已经从幕后走到了前台,成为推动科技进步和社会变革的关键力量。编写代码、解决问题、不断学习新技术,程序员们的日常充满了挑战与…

SpringMVC拦截器应用实例与优化

前言 本文将介绍如何使用SpringMVC的拦截器的基本使用 拦截器概念 SpringMVC拦截器(Interceptor)是一种动态拦截方法调用的机制,它能够在指定的方法调用前后执行预先设定的代码,甚至阻止原始方法的执行。拦截器在Spring MVC框架中…

利士策分享,美国“假旗”行动,是否成为了网络空间的阴霾?

利士策分享,美国“假旗”行动,是否成为了网络空间的阴霾? 在当今这个信息化时代,网络空间已经成为国家间竞争与合作的重要领域。然而,美国却频繁采取一种名为“假旗行动”的卑劣手段,污染全球网络空间,给世…

《最优化方法》

课件是学习的核心内容 这门课,作业自己交,但是老师不做记录,上课不点名, 不记录平时成绩。 第一章 最优化问题的概述 1.1 概述(和考试内容无关,了解内容) 例题1.1.1运输问题 数学模型&#x…

(37)使用MATLAB画出余弦波的频谱

文章目录 前言一、MATLAB仿真代码二、仿真结果画图 前言 首先使用MATLAB生成一段余弦信号,然后对其进行FFT变换,画出其频谱。 一、MATLAB仿真代码 代码如下: f [50, 100]; % 两个余弦波的频率 fs 1000; …

论文 | OpenICL: An Open-Source Framework for In-context Learning

主要内容: 2. 提供多种 ICL 方法: 3. 完整的教程: 4. 评估和验证: 背景: 随着大型语言模型 (LLM) 的发展,上下文学习 (ICL) 作为一种新的评估范式越来越受到关注。问题: ICL 的实现复杂&#xf…

springboot在线医疗问答平台

基于springbootvue实现的在线医疗问答平台 (源码L文ppt)4-088 4 系统设计 4.1 功能模块设计 在线医疗问答平台根据权限类型进行分类,主要可分为用户、医生和管理员三大模块。用户、医生模块主要实现了修改个人信息,查看…

力扣题31~40

题31(中等): 分析: 其实这题题目比较难懂,题目还是挺简单的 我们可以从后面末尾开始,如果前一个大于后面的,说明后面不用动,如果小于,那就找仅仅大于它的数字放前面&…

一个将.Geojson文件转成shapefile和kml文件的在线页面工具

最近需要读取.geojson格式的流域边界文件。在谷歌地球桌面版和globalMapper中均无法正常读取。下面我发现的一个在线的平台可以很好实现这一功能。 GeoJSON to SHP Converter Online - MyGeodata Cloud ❤️欢迎点赞收藏❤️

2000.1-2024.7中国经济政策不确定性指数(月度)

2000.1-2024.7中国经济政策不确定性指数(月度) 1、时间:2000.1-2024.7 2、指标:Date、CNEPU 3、来源:China Economic Policy Uncertainty Index 4、说明:中国经济政策不确定性指数,用于衡量…

MongoDB安装保姆级教程

安装MongoDB 1.下载地址 https://www.mongodb.com/try/download/community 这里选择的5版本的。 2.选择zip下载 (也可以选择msi一步步安装) 3.配置环境变量 将MongoDB的bin目录添加到path下 E:\JavaPackage\mongodb\bin 4.检查是否配置成功 cmd里执行 mongod WINR&…

JavaSE——集合12:Map接口实现类—Properties

目录 一、Properties基本介绍 二、Properties常用方法 一、Properties基本介绍 Properties类继承自HashTable类并且实现了Map接口,也是使用一种键值对的形式,来保存数据。Properties的使用特点和HashTable类似Properties还可以用于从xxx.properties文件…

“我们为什么缺少科学精神”演讲内容拆解

演讲人张双南,视频链接: https://tv.cctv.com/2017/04/23/VIDEdqzdpmxStYXAmYBdgDP7170423.shtml