4.7 为什么 TCP 每次建立连接时,初始化序列号都要不一样呢?

文章讨论了TCP连接中如何通过不同序列号策略,如使用随机生成的初始化序列号和时间戳机制,防止历史报文被错误接收。特别强调了PAWS(Pre-AcknowledgmentWindowsScaling)防回绕序列号算法的重要性。

主要原因是为了防止历史报文被下一个相同四元组的连接接收。

如果正常通过四次挥手完成,TIME_WAIT状态会持续2MSL,历史报文会在下一个连接之前就自然消失,但无法保证每次连接都能通过四次挥手正常关闭。

  • 假设客户端和服务端建立一个连接后,客户端发送包被网络阻塞了,然后超时重传了这个数据包,而此时服务端设备断电重启了,之前与客户端建立的连接就消失了,于是在收到客户端的数据包的时候就会发送RST报文。
  • 这时候客户端和服务端再次建立相同四元组的连接。
  • 在新连接建立完成后,上一个连接中被网络阻塞的数据包正好抵达了服务端,刚好历史数据报文的序列号在服务端接收窗口的范围内,所以该数据包会被服务端正常接收,数据错乱。

如果每次建立连接客户端和服务端的初始化序列号都「不一样」,就有大概率因为历史报文的序列号「不在」对方接收窗口,从而很大程度上避免了历史报文,不是完全可避免

客户端和服务端的初始化序列号都是根据计数器递增的随机数产生的,基本不会产生一样的初始化系列号。

  • 序列号:序列号是一个 32 位的无符号数,因此在到达 4G 之后再循环回到 0
  • 初始序列号:客户端和服务端都会各自生成一个初始序列号,它是基于时钟生成的一个随机数,来保证每个连接都拥有不同的初始序列号。初始化序列号可被视为一个 32 位的计数器,该计数器的数值每 4 微秒加 1,循环一次需要 4.55 小时

序列号和初始序列号并不是无线递增的会发生回绕为初始值的情况,这意味着无法根据序列号来判断新老数据,需要事件戳解决tcp_timestamps 便于精确计算 RTT ,另一个是能防止序列号回绕(PAWS)

防回绕序列号算法,要求连接双方维护最近一次收到的数据包的事件戳每收到一个新数据包都会读取数据包中时间戳值跟Recent TSval值作比较,如果发现收到的数据包中时间戳不是递增的,则表示该数据包是过期的,就会直接丢弃这个数据包

总结:

客户端和服务端的初始化序列号都是根据计数器底层的随机数,随机生成的,能很大程度上避免历史报文被下一个相同的四元组的连接接收,然后有引入时间戳机制,从而完全避免历史报文被连接接收的问题。

时间戳回绕:

增加时间戳的大小,由32 bit扩大到64bit

将一个与时钟频率无关的值作为时间戳,时钟频率可以增加但时间戳的增速不变

<think>嗯,用户问的是为什么需要初始化GPIO,以及GPIO的作用。首先,我得回忆一下GPIO的基本概念。GPIO是通用输入输出端口,微控制器通过它和外部设备连接。作用的话,可能包括控制LED、读取传感器信号等等。 那为什么初始化呢?初始化应该是为了配置引脚的工作模式,比如输入还是输出,是否上拉下拉,速度等。同的外设需要同的配置,比如控制LED可能需要推挽输出,而读取按键可能需要上拉输入。如果初始化,引脚的状态确定,可能导致设备无法正常工作或者损坏。 接下来需要分点说明GPIO的作用和初始化的原因。可能用户是刚开始学嵌入式,所以解释要避免太专业的术语,用例子帮助理解。比如用LED和按键的例子说明输入输出模式的同应用。 还要注意结构清晰,按照用户的要求逐步解释。可能需要先讲GPIO的作用,再讲为什么需要初始化,最后总结。确保每个部分都有例子,比如初始化设置模式、速度、上下拉电阻,这些配置对电路的影响。 另外,用户可能隐含的问题是,初始化步骤具体做了什么,或者初始化会有什么后果。所以在回答中需要提到默认状态可能符合需求,初始化确保正确配置,避免信号冲突或者功耗问题。 检查是否有遗漏的点,比如GPIO的其他功能,比如复用为其他外设引脚,这也需要在初始化配置。还有同微控制器可能有同的库函数,但初始化的目的是一致的。需要确认这些信息是否相关,用户可能想知道通用的原因,而是特定型号的配置步骤。 最后确保语言口语化,避免使用复杂的句子,用“比如”、“例如”来连接例子,帮助用户理解。可能需要提醒用户,具体初始化步骤参考数据手册,因为同厂商可能有差异。</think>GPIO(General Purpose Input/Output,通用输入输出端口)是微控制器与外部设备进行数字信号交互的核心接口。以下是分步说明: 一、GPIO的作用 1. 信号传输通道 - 输出模式:控制外部设备(如:驱动LED亮灭,控制继电器开关) $$ V_{out} = \begin{cases} 3.3V & \text{高电平} \\ 0V & \text{低电平} \end{cases} $$ - 输入模式:读取外部信号(如:检测按键状态,接收传感器数字信号) 2. 电气特性可配置 - 支持推挽/开漏输出模式 - 可配置上拉/下拉电阻(典型值:4.7kΩ~10kΩ) - 支持多级驱动能力调节(如:2mA/10mA/25mA) 二、必须初始化的原因 1. 确定工作模式 - 未初始化的GPIO处于高阻态(Z状态),无法可靠传输信号 - 需明确设置为: * 输入模式(浮空/上拉/下拉) * 输出模式(推挽/开漏) * 复用功能(如USART、I2C等) 2. 配置电气参数 - 设置输出速率(如:2MHz/10MHz/50MHz) - 配置驱动能力(防止过流损坏电路) - 匹配外部电路阻抗(避免信号反射) 3. 避免冲突和功耗 - 默认状态下多个GPIO可能短接 - 未初始化引脚可能产生漏电流(典型值:μA级) - 防止上电瞬间出现意外电平跳变 三、初始化流程示例(以STM32为例) ```c GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_5; // 选择引脚5 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式 GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉/下拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速模式 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 应用配置到GPIOA ``` 四、典型应用场景 1. LED控制:需配置为推挽输出 2. 按键检测:需配置为上拉输入(外部接地按键) 3. 数字传感器:根据传感器要求配置为开漏输出或浮空输入 总结:GPIO初始化就像给电路板上的"开关"设置规则,确保每个引脚都能按照设计要求正确、安全地工作。如同未设置参数的晶体管无法正常工作一样,未经正确初始化的GPIO可能导致系统稳定、功能异常甚至硬件损坏。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值