【LwIP源码学习3】TCP协议栈分析——数据接收流程
前言
本文介绍代码在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);
相关文章:

【LwIP源码学习3】TCP协议栈分析——数据接收流程
前言 本文介绍代码在lwip的tcp_in.c文件中,主要介绍TCP协议栈中数据的接收流程。 正文 1、一个正常的TCP数据,首先会传入到 tcp_input(struct pbuf *p, struct netif *inp)函数,其中指针p指向传入的数据流。 2、从数据流中获取TCP头部 …...

【bug】finalshell向远程主机拖动windows快捷方式导致卡死
finalshell向远程主机拖动windows快捷方式导致卡死 问题描述 如题,作死把桌面的快捷方式拖到了finalshell连接的服务器面板中,导致finalshell没有响应(小概率事件,有时会触发) 解决 打开任务管理器查看finalshell进…...

基于SpringBoot剧本杀管理系统 【附源码】
基于SpringBoot剧本杀管理系统 效果如下: 系统首页界面 系统注册页面 剧本信息详细页面 后台登录界面 管理员主界面 剧本信息界面 剧本预约界面 作者主界面 研究背景 随着现代社会生活节奏的加快,人们越来越渴望通过各种娱乐活动来释放压力和增进社交…...
Linux 命令 —— grep、tail、head、cat、more、less(查看日志常用命令)
文章目录 查看日志常用命令grep 命令tail 命令head 命令cat 命令more 命令less 命令 查看日志常用命令 grep tail、head、cat、more、less grep 命令 grep [options] PATTERN filename:查找日志文件中的 PATTERN 关键字,用于过滤/搜索的特定字符。PAT…...
知识见闻 - 美国连线杂志
https://www.wired.com/ WIRED 杂志是一份月刊,重点关注新兴技术如何影响文化、经济和政治。在快速变革的世界中,它已成为信息和思想的重要来源。 WIRED magazine is a monthly publication that focuses on how emerging technologies impact culture, …...

多线程的状态及切换流程
多线程的状态及切换流程 线程状态说明: 初始化(Init):该线程正在被创建。就绪(Ready):该线程在就绪列表中,等待 CPU 调度。运行(Running):该线程…...

[Python学习日记-47] Python 中的系统调用模块—— os 与 sys
[Python学习日记-47] Python 中的系统调用模块 简介 os sys 简介 os 模块和 sys 模块提供了很多允许你的程序与操作系统直接交互的功能。下面将进行逐一介绍。 os 一、os.getcwd() 得到当前工作目录,即当前 Python 脚本工作的目录路径(绝对路径&#…...

Linux系统——lvm逻辑卷
Linux系统——lvm逻辑卷 一、lvm逻辑卷1、lvm操作流程2、操作指令 二、逻辑卷操作1、创建逻辑卷1.1 /dev/cloud/openstack 5G xfs /cloud/openstack1.2 /dev/cloud/docker 10G ext4 /cloud/docker 2、逻辑卷扩容2.1 扩容流程2.2 需求一:扩容ext4文件系统的逻辑卷2.3…...

一键快捷回复软件助力客服高效沟通
双十一临近,电商大战一触即发!在这个购物狂欢的热潮中,客服团队的效率至关重要。今天我要和大家分享一个非常实用的快捷回复软件,特别是为电商客服小伙伴们准备的。这款软件能够极大地提高你的工作效率,让你在处理客户…...

初识Linux之指令(二)
一:head指令 head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的 开头至标准输出中,而 tail 想当然尔就是看档案的结尾。 语法:head 【参数】 【文件】 功能&…...
在深度学习中,Epoch、迭代次数、批次大小(Batch Size)和学习速率(Learning Rate)是影响模型训练效果的重要超参数。
1. Epoch 定义:Epoch是指整个训练数据集被完整地用来训练一次。影响:增加Epoch的数量可以使模型更充分地学习数据。然而,过高的Epoch可能导致过拟合,即模型在训练集上表现良好,但在测试集上表现不佳。设置:…...
研究学习的循环递进三段论
在研究学习,编程语言、编译器、计算机科学、类型论、集合论等多门学科及分支后,我貌似隐隐约约地感受到,研究学习的过程分为三个阶段,我称之为研究学习的三段论,其中的段,是阶段的意思。对应了,…...

Linux下如何将代码提交至Gitee
首先在gitee中创建自己的仓库. 下面是已经创建好的仓库 然后复制仓库的链接(点击上图克隆/下载) 接下来打开linux, 1.在命令行输入git clone 链接 2. 输入ll,即可看到linux-course项目仓库 3.cd linux-courses(进入项目仓库) 4.在仓库中可以随意增加文件 例如增加test.c文件…...

【MATLAB源码-第181期】基于matlab的32QAM调制解调系统频偏估计及补偿算法仿真,对比补偿前后的星座图误码率。
操作环境: MATLAB 2022a 1、算法描述 在通信系统中,频率偏移是一种常见的问题,它会导致接收到的信号频率与发送信号的频率不完全匹配,进而影响通信质量。在调制技术中,QPSK(Quadrature Phase Shift Keyi…...
24年856电子线路专业课考场回忆
856考试包含了模电与数电两大部分,24年题型结构为14题选择与14填空,上去大约花了半个小时搞定,唯一记得有几个纠结点:1、开关型稳压电路中开关管怎么接是升压,2、字扩展与位扩展的区别。 接下来就是第三部分的分析计算…...

el-table表格里面有一条横线
表格里面 有一条横线, 出现原因:是自定义了表格头.使用了固定列(fixed),定宽。就很难受。。。 添加样式文件: <style lang"scss" scoped>::v-deep {.el-table__fixed-right {height: 100%…...
QT通过QLocalSocket和QSharedMemory实现进程间通信
文章目录 QLocalSocket和QLocalServer客户端服务端QSharedMemory加载数据到共享内存从共享内存中读取数据进程间通信(Inter-Process Communication, IPC)是指在不同进程之间进行数据交换和消息传递的机制。由于不同进程之间在内存和资源使用上的隔离,IPC 是操作系统提供的一种…...

Python中的数据可视化艺术:用Matplotlib和Seaborn讲故事
Python中的数据可视化艺术:用Matplotlib和Seaborn讲故事 数据可视化不仅仅是图表的绘制,更是通过视觉形式传达复杂信息的一种艺术。使用Python中的两个强大的库——Matplotlib和Seaborn,可以将数据转化为清晰、优美的图表,帮助我…...
python机器学习(手写数字识别)
# 导包 import matplotlib.pyplot as plt import pandas as pd from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier import joblib from collections import Counter # 1. 定义函数 show_digit(idx), 用于查看: 数字图…...

如何针对项目中的技术难点准备面试?——黑马点评为例
最核心的,包装和准备 个人项目,怎么包装?一定要写出代码才可以吗? 你可以在系统A中实现就可以,了解其中实现的细节,怎么跟面试官对线等等,这些话术到位了之后,再把它融入到系统B&a…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...

【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
Java多线程实现之Runnable接口深度解析
Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...