分类: 未分类

  • Ventoy启动Windows镜像

    ventoy可以直接启动iso和磁盘镜像中的系统,这样就可以实现在一个U盘中共享多个系统,而且U盘只需要一个NTFS分区就可以。

    1. 下载ventoy
      https://www.ventoy.net/cn/download.html
    2. 初始化U盘

    3. 下载ventoy_vhdboot.zip

    下载地址:https://github.com/ventoy/vhdiso/releases

    下载后解压其中的ventoy_vhdboot.img到U盘ventoy目录

    4. 制作Windows10/Windows11的vhd(x)镜像

    可以用wintogo制作工具生成vhd(x)镜像,也可以在虚拟机(建议virtualbox或hyper-v)中按装Windows,然后再把vhd(x)格式的虚拟硬盘拷出来放到U盘根目录。

    关于如何解决UEFI签名的问题请参考ventoy的文档

    Views: 0

  • 雷电接口

    以最新的雷电5和USB4 v2.0为例,两种技术在标准上是相同的,但是雷电5是Intel认证的,USB4是USB-IF认证或干脆没有认证。雷电5就是USB4的完全体,并加强了充电功率。Intel认证的时候是按最高规格来的,USB-IF则会放宽标认证标准,比如在USB4.0上可选的功能在雷电5中都是强制要求的,USB4.0也会有更低速率的版本(低于对称80Gbps,非对称120/40Gbps),其实USB4.0 v2.0与雷电5在速率上的要求也是一样的。

    不过现有的雷电5/USB4 v2都是基于PCIe4.0X4接口,最高只有单向64Gbps的速率,与CPU通信时也不会完全体的80Gbps,以后可能会有PCIe5.0X4接口的吧,至于非对称的120/40Gbps主要用于与显卡通迅跟PCIe带宽没有多大关系。雷电5/USB4 v2线缆长度要求不能超过1米。

    Intel出的雷电5控制器有JHL9480和JHL9580。

    Views: 0

  • Mellanox网卡驱动的安装

    旧的驱动是mlnx_ofed,mlnx_ofed应该不会再添加新功能的,新的驱动架构换成了doca_ofed。

    参考:

    https://docs.nvidia.com/doca/sdk/doca-host+installation+and+upgrade/index.html#src-3653456226_id-.DOCAHostInstallationandUpgradev3.0.0-InstallingSoftwareonHost

    https://docs.nvidia.com/doca/sdk/mlnx_ofed+to+doca-ofed+transition+guide/index.html#src-3453015790_id-.MLNX_OFEDtoDOCAOFEDTransitionGuidev2.9.1-InstallationExampleofDOCA-OFEDfromOnlineRepo

    创建文件/etc/apt/sources.list.d/doca.list,内容为:

    deb [signed-by=/etc/apt/trusted.gpg.d/GPG-KEY-Mellanox.pub] https://linux.mellanox.com/public/repo/doca/2.10.0/ubuntu24.10/x86_64/ ./

    然后执行

    apt update

    apt install doca-ofed

    doca-ofed主要是在宿主机上安装使用,KVM客户机用系统自带驱动就可以。

    Views: 0

  • mellanox网卡对shampo的支持

    目前看到的资料是仅ConnectX-7以上的网卡才支持,而且我ConnectX-4 LX的网卡确实用不了。

    参考以下内容:

    https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next/+/7da375e2c7e023957b71fce44a72107559cfa6d0%5E1..7da375e2c7e023957b71fce44a72107559cfa6d0

    https://forums.developer.nvidia.com/t/stride-size-in-multi-packet-and-how-to-enable-shampo-in-connectx-6/232013

    如果用的是ConnectX-7网卡的话可以用以下命令开启:

    ethtool -K enp2s0f0np0 rx-gro-hw on

    Views: 0

  • ubuntu虚拟机克隆后DHCP获取到的IP地址不会变

    可以看到MAC地址是不同的,但是DHCP就是获取不到新的IP

    rm /etc/machine-id
    systemd-machine-id-setup
    echo new-hostname > /etc/hostname
    修改/etc/hosts中的主机名
    最后reboot

    Views: 1

  • TCP的拥塞控制算法对比

    • Tahoe

    这是最古老经典的拥塞算法,也就是常说的慢启动/拥塞避免机制。Tahoe的速率波动曲线如下: 拥塞控制过程 ssthresh是慢启动到拥塞避免的临界值,始终是上一次发生拥塞时窗口的一半,Tahoe在第一次拥塞避免结束后会直接把拥塞窗口降到1MSS,然后重新执行慢启动和拥塞避免。

    • Reno

    相对Tahoe算法Reno算法在发生快速重传后进入恢速恢复状态而不是慢启动状态,这样带宽惩罚更小。当然发生RTO(超时重传)后还是会进入慢启动状态。 Reno拥塞控制

    • BIC

    BIC的全称是Binary Increase Congestion,通过二分查找更快的找到最快速度。

    • Cubic

    CUBIC使用三次方函数提高拥塞避免阶段速率提升速度(其实是现慢后快),同时解决了RTT公平性问题。 传统的拥塞避免算法(Reno)基于RTT周期来增加发送速率,RTT越小的连接速度启动越快,这样对高延迟连接就很不公平,CUBIC的拥寒避免不再与RTT挂钩而是与固定时间挂钩。 在快速恢复状态下速减少到原来的70%而不是50%。 BIC和Cubic的慢启动和Reno都是一样的,都是倍增方式,区别主要是拥塞避免阶段,Cubic相比BIC速率波动更平缓,解决了RTT公平性问题。

    • BBR

    BBR会周期性的探测当前的实际延迟(RTprop)和带宽(BtlBw),RTprop和BtlBw是BBR引入的两个术语,表示当前网络的物理延迟和带宽。BBR会周期性的提高发送速率(25%)来探测BtlBw有没有增加,降低发送速率(inflight = 4,未确认包为4)来探测RTprop有没有减少。使用RTprop剩以BtlBw得到BDP(带宽延迟积),BDP表示正在飞行中(在传输管道中)的数据量,也即是未确认的数据量。当inflight大于BDP时cwnd会变满,会停止发送数据。

    现代网络设备都有很大的队列缓存,当发生拥塞时数据会排队,然后就会引起延迟增加,不利于延迟敏感应用,使用BBR算法可以避免拥塞时产生的延迟增加或网络中断。

    BBR算法probeBw周期是8个RTT,在稳定状态始终执行probeBw,这8个RTT周期对应的pacing_gain系数分别是1.25,0.75,1,1,1,1,1(probeBw就是通过控制pacing_gain来执行的),即1个RTT加速,1个RTT减速,剩余4个RTT匀速发送。(这个周期是参考网上别人的笔记和deepseek(怀疑deepseek也是网上抄来的),具体是不是这样还要结合源代码和IETF文档来验证) 但是probeRTT是每10s执行一次(固为RTTprop变化频率低,且测量RTTprop会影响带宽)。 BBRv1已经合并linux主线分支,但BBRv3尚没有合并(截止linux 6.15 RC5),v2应该只是实验版本不会对外发布,v3包含v2的功能。BBRv3修复了诸多bug,降低了重传序和延迟,与Cubic更好的共存,支持ECN等。

    • GCC

    GCC是WebRTC中默认的拥塞控制算法,可以同时基于丢包和延迟进行拥塞控制,相比BBR算法传输速率更稳定,延迟更低,抗丢包能力强,丢包率50%时仍能使用,但带宽利用率不如BBR。

    TCP拥塞控制算法多如牛毛,以上是主要的几个算法。CUBIC算法可能存在的一个问题是bufferbloat。

    Views: 1

  • TCP的拥塞控制

    • 拥塞窗口

    在TCP发送端有3个窗口,分别是发送窗口,滑动窗口,拥塞窗口。发送窗口就是实际生效的窗口,发送窗口的大小等于滑动窗口和拥塞窗口中的较小者。

    • 拥塞控制

    发送速率按倍数指数增加,当发生拥塞时速率减半

    • 拥塞避免

    发送速率按MSS数量线性增加,每经过一个RTT增中1个MSS,当发生拥塞时速率降低一个MSS。

    • 慢启动

    在慢启动开始时执行拥塞控制快速达到最大带宽,然后降低发送速率再以拥塞避免的方式缓慢增加发送速率。 在执行拥塞避免的过程中会不断达到最大发送速率进入拥塞状态,然后再降低速率,如此往复发送速率会出现矩齿形波动。

    • 快速恢复

    新版TCP(Reno)选择跳过丢包后收到三次重复ACK的慢启动过程,直接进入拥塞避免阶段,这就是所谓的快速恢复,但是超时重传后还是会进入慢启动的。

    • 快速重传

    在TCP确认机制中已经讲过快速重传,当快速重传触发时也会同步触发拥塞控制,从而将拥塞窗口减半,对于CUBIC算法则窗口大小会减少20%至30%,BBR算法则窗口大小会减少10%至20%。

    • ECN

    当即将发生丢包或延迟增加时路由器或者防火墙提前通过ECN标志告诉发送方即将发生拥塞,从而降低发送速率以避免实际发生丢包或延迟增加。相当于拥塞预警标志。 这个标志会同时出现在IP报头和TCP报头中,以便于路由器操作。 IP报文中的ECN标志用于路由器向接收方发送的报文中携带拥塞预警标志,TCP报文中的ECN标志用于接收方把路由器在IP报文中的拥塞预警反映给发送方。 ECN可以实现零丢包,低时延的的拥塞控制,但支持ECN的防火墙,路由器,交换机非常少,华为也只有部分支持智能无损网络的交换设备才支持。

    参考:https://segmentfault.com/a/1190000044452754

    • CUBIC

    Reno算法的速率提升还是太慢了,尤其对于短时连接,数据发完了还没达到最大速率。CUBIC使用三次方函数进一步提高拥塞避免阶段的速率提升速度(取代之前的线性提速),同时解决了RTT公平性问题。 传统的拥塞避免算法(Reno)基于RTT周期来增加发送速率,RTT越小的连接速度启动越快,这样对高延迟连接就很不公平,CUBIC的拥塞避免不再与RTT挂钩而是与固定时间挂钩。

    • BBR

    BBR会周期性的探测当前的实际延迟(RTprop)和带宽(BtlBw),RTprop和BtlBw是BBR引入的两个术语,表示当前网络的物理延迟和带宽。BBR会周期性的提高发送速率(25%)来探测BtlBw有没有增加,降低发送速率(inflight = 4,未确认包为4)来探测RTprop有没有减少。使用RTprop剩以BtlBw得到BDP(带宽延迟积),BDP表示正在飞行中(在传输管道中)的数据量,也即是未确认的数据量。当inflight大于BDP时cwnd会变满,会停止发送数据。

    现代网络设备都有很大的队列缓存,当发生拥塞时数据会排队,然后就会引起延迟增加,不利于延迟敏感应用,使用BBR算法可以避免拥塞时产生的延迟增加或网络中断。

    BBR算法probeBw周期是8个RTT,在稳定状态始终执行probeBw,这8个RTT周期对应的pacing_gain系数分别是1.25,0.75,1,1,1,1,1(probeBw就是通过控制pacing_gain来执行的),即1个RTT加速,1个RTT减速,剩余4个RTT匀速发送。(这个周期是参考网上别人的笔记和deepseek(怀疑deepseek也是网上抄来的),具体是不是这样还要结合源代码和IETF文档来验证) 但是probeRTT是每10s执行一次(固为RTTprop变化频率低,且测量RTTprop会影响带宽)。 BBRv1已经合并linux主线分支,但BBRv3尚没有合并(截止linux 6.15 RC5),v2应该只是实验版本不会对外发布,v3包含v2的功能。BBRv3修复了诸多bug,降低了重传序和延迟,与Cubic更好的共存,支持ECN等。

    https://datatracker.ietf.org/doc/draft-ietf-ccwg-bbr/02/ https://zhuanlan.zhihu.com/p/142835569 https://cloud.tencent.com/developer/article/1482633 https://zhuanlan.zhihu.com/p/675308313

    Views: 1

  • 滑动窗口,TCP的流量控制机制

    TCP 协议与包括 UDP 在内的其他传输层协议的主要差别在于:数据传输质量UDP 协议将数据发送出去之后就不管了,但 TCP 还会对已发送的数据进行跟踪,以防丢失。这样就有效地实现了 TCP 协议的两个关键特性:

    • 可靠性reliability ),保证数据可靠送到目的地(如有丢失,必须能够检测出来,并重传);
    • 流量控制flow control ),控制数据发送速度,以免冲垮接收方;

    为实现这两个设计目标,TCP 协议引入了所谓的 滑动窗口sliding window )机制。理解滑动窗口机制,是掌握 TCP 协议的关键,也是学习其他 TCP 知识的前提。本节带领大家将滑动窗口机制一举拿下!

    UDP局限性

    UDP 数据包完全依赖 IP 包进行网际传输,可以看作是加上端口号的 IP 包而已。因此,UDP 协议的传输质量完全取决于 IP 包。由于 IP 协议只是一种“尽力而为”的网络协议,不能保证可靠性,因而 UDP 也是不可靠的。

    由于网络链路问题,IP 包在传输的过程中随时可能丢包,承载在其上的 UDP 包也肯定会丢。如上图,发送方通过 UDP 协议给接收方发送 4 个数据报,其中承载数据③的 IP 包丢失了,但双方均不知情。

    一个数据报发送出去后,可能会到达目的地,也可能不会。由于发送方无法从接收方那得到任何反馈,因而无法保证可靠性,流量控制就更别提了。因此,我们需要在 IP 协议之上,引入额外的机制,来处理丢包问题。

    确认机制

    由于 IP 协议缺乏反馈机制,为保证可靠性,TCP 协议规定:当接收方收到一个数据后,必须回复 ACK 给发送方。这样发送方就能得到反馈,如果数据发出去后很长时间都没有收到 ACK 确认,说明数据很有可能已经丢失了。

    一旦数据在传输过程中丢失,发送方必须重传。因此,TCP 每次发送数据后,都会启动一个定时器。如果定时器超时还没收到对方确认,TCP 就会重新发送数据。我们来看一个例子:

    图中左边是发送方待发送字节流状态,字节流中每个字节都有一个序号,假设从零开始。数据颜色代表发送状态:

    • 灰色,表示已经发出去而且收到对方确认的数据;
    • 蓝色,表示已经发出去但还未收到确认的数据;
    • 绿色,表示还未发送的数据(包括未来要发但此刻还不存在的数据);

    刚开始时,发送方已经成功发送了前 5 个字节,如灰色部分所示。随后它开始发送数据①,其实序号为 5 ,总共 5 个字节。再啰嗦一句,起始序号 5 保存在 TCP 报文段中的序号字段;而数据长度 5 无须保存,TCP 可以根据 IP 包数据长度和 TCP 头部长度来计算。

    发送方在发送数据的同时,启动了一个计时器。这些数据虽然已经发送出去了,但还没收到对方确认,因而处于蓝色状态。随后它收到接收方发来的确认,状态转为灰色,万事大吉!注意到,确认号是最后一个字节加一,也就是下一个数据的起始序号。

    紧接着,发送方又发出了数据②,首字节序号为 10 ,总共 4 个字节。这次比较背,数据②在传输过程中丢失了!发送方等到计时器超时都没收到确认,因此它将数据重新发送一次,并再次启动计时器。

    这时,数据②仍维持蓝色不变,因为发送方还没收到确认。等数据成功送达对方,并收到对方的确认后,数据转成灰色状态。待发送字节流颜色不断交替,滚滚向前。

    接收缓冲区

    由于承载 TCP 报文段的 IP 包是独立路由的,可能走不同的网络路径,无法保证一定按照发送顺序送达目标主机。 TCP 协议需要向上提供连续字节流传输服务,如果报文段错序到达,TCP 必须根据序号重新排列数据。

    另一方面,数据到达后目标主机后,接收方应用程序可能忙于其他事情,无法及时处理。鉴于这两个点,TCP 接收方需要在内存中准备一个接收缓冲区,用于临时保存数据。

    TCP 报文段到达后,数据先临时保存在缓冲区中,位置由序号决定。当相邻的数据均达到后,组成连续字节流提交给应用程序。当应用程序将数据取走后,缓冲区中的副本就可以删除。如果应用程序忙于其他任务,数据则继续缓存在缓冲区中。

    TCP 协议一般由操作系统内核实现,应用程序只需通过系统调用发送/接收数据,完全不用关心序号或 ACKTCP 数据到达后,内核先将其保存于接收缓冲区,再通知应用程序读取。

    我们来看一个新例子,这次站在接收方的角度,考察数据流在接收缓冲区中的状态:

    1. 刚开始时,接收方缓冲区已接收了 5 字节数据,但应用程序尚未读取;
    2. 发送方又发来 5 字节数据,接收方回复 ACK ,数据保存在缓冲区,应用程序仍未读取;
    3. 与此同时,接收方通告窗口大小为 5 字节,表示自己还能接收 5 字节数据(超过缓冲区就会溢出);
    4. 应用程序将缓冲区中的 10 字节数据全部读取,接收方通告新窗口大小为 15 字节;
    5. 发送方又前后发来两份数据,分别是数据②和数据③,大小均为 4 字节;
    6. 其中,数据②在网络中丢失了;
    7. 数据③顺利到达,接收方根据序号将其保存在缓冲区中,并回复 ACK ,确认号和窗口均不变;
    8. 由于数据②尚未到达,未能组成连续数据提交给应用程序;
    9. 因长时间没收到 ACK ,发送方重传数据②(数据③也被重传,因为 ACK 只确认 10 以前的数据);
    10. 数据②顺利到达,接收方将其保存在缓冲区中,并回复 ACK (注意确认号,数据③也一并确认了);
    11. 数据②和数据③组成连续数据,可以提交给应用程序读取;

    综上所述,接收缓冲区主要起到两个关键作用:

    • 应用进程繁忙时暂存数据
    • 数据乱序到达时重排数据

    流量控制

    接收缓冲区大小是有限的,如果应用进程处理缓慢,发送方还拼命发送,最终肯定会压垮接收方。因此,当缓冲区有变化时,接收方应该通过 窗口大小 字段,将它的剩余大小告知发送方。

    接收方通告的窗口大小通常称为 通告窗口advertised window ),可缩写为 awnd 。它起到约束发送方发送速度的作用:

    • 如果接收方应用进程繁忙,迟迟未读取缓冲区里的数据,那么窗口大小将慢慢变小;
    • 当窗口大小降为零,发送方就停止发送新数据;

    通过通告窗口,发送方可以实时感知接收方缓冲区的状态,然后根据缓冲区剩余空间动态调整发送速度,这就是 TCP流量控制flow control )机制。

    滑动窗口

    重新站在发送方的角度,来考察数据的发送状态,可以分为四种:

    1. 已发送且已确认,这部分已经发送完毕,可以忽略;

    2. 已发送但未确认,这部分可能在网络中丢失,数据必须保留以便必要时重传;

    3. 未发送但可发送,这部分接收方缓冲区还有空间保存,可以发出去;

    4. 未发送且暂不可发送,这部分已超出接收方缓冲区存储空间,就算发出去也没意义;

    注意到,第②和第③部分加起来就刚好是接收方缓冲区大小,如图红框部分。红框的左边缘由接收方的最后一个 ACK 确认决定,而长度由接收方通告的窗口大小决定,它规定了当前发送方能发送的最大数据量。

    当发送方收到对方的 ACK ,意味着有数据已成功到达接收方,窗口左边缘将向右移动:

    当接收方应用进程将数据从缓冲区取出后,向接收方通告新的窗口大小,这时窗口右边缘向右扩张:

    随着双方通信的进行,由 已发送但未确认 以及 未发送但可发送 这两部分数据组成的窗口将不断向右移动,因此被形象地称为 滑动窗口sliding window ),TCP 流量控制机制也因此被称为滑动窗口机制。

    延迟确认

    TCP 协议规定,接收方收到数据后,必须发送 ACK 进行确认,以此实现可靠传输。然而,就算是一个小小的 ACK 确认,也需要一个完整 TCP 分组报文来承载,开销很大!

    众所周知,最小的 TCP 分组包含 20 字节的 TCP 头部和 20 字节的 IP 头部,总共 40 字节。试想发送一个 40 字节的 TCP 报文,仅仅只为了告诉发送方 4 字节的确认号,效率得有多低!有效信息才占 10%

    为了提高传输效率,TCP 实现了 延迟确认delayed ACK )机制。延迟确认顾名思义就是收到数据不立马确认,而是等上一段时间,跟其他数据一起发送。我们来看几个例子:

    第一个例子,发送方连续发来 4 个数据,原本需要发送 4ACK 确认。启用延迟确认后,第一个 ACK 都稍作延迟跟后一个 ACK 一起合并发送。这样一来,每两个数据发送一个确认,效率提高一倍!

    第二个例子,发送方发来 1 个数据,但是 TCP 没有立马发送 ACK 确认(灰色)。后来,接收方也要发送数据了, ACK 确认被捎带在数据分组里面进行回复。ACK 确认和数据一起拼车,省掉一个分组报文(灰色)。

    你可能有疑问,如果收到数据后,短时间没有其他数据要发送,怎么办?其实很简单,请看第三个例子:TCP 收到数据后会启动一个定时器,定时器超时后就立马发送 ACK 确认(绿色)。

    总结

    • TCP 双方实现接收确认机制,保证数据可靠传输;
    • 接收方引入缓冲区实现数据重排,以及在应用进程繁忙时暂存数据
    • 接收方通过窗口大小字段实时通告缓冲区剩余空间;
    • 发送方根据接收方通告的窗口大小,控制发送速度,以免冲垮接收方;
    • 由最新 ACK 和通告窗口大小划定的数据区域称为 通告窗口 ,发送方据此实现 流量控制

    转载自:https://fasionchan.com/network/tcp/sliding-window/

    转载总结:

    滑动窗口包含了已发送但未确认和可发送但尚未发送的数据大小,每确认一个分段滑动窗口左边界向右移动,接收者缓冲区每提交一个分段滑动窗口右边界向右移动。所以对于发送者来说窗口大小和边界一直是动态变化的。

    接收者也可以通过窗口通告主动减小窗口大小让窗口右边界往左移动。

    通常窗口通告随ACK报文一起发送。

    当发送方一直收不到窗口大小通告,窗口大小变会变为0,然后就会停止发送数据,然后就要定期发送零窗口探测报文,接收者回复新的窗口大小,直到窗口大小大于0为止。

    Views: 1

  • TCP的确认和重传机制

    TCP的确认和重传机制

    • 基本确认机制

    接收方每收到一个TCP分段都会回应一个ACK号,ACK号等于下一次发送报文的序列号。
    累积确认是TCP的强制特性,所有TCP实现都要实现这一特性。ACK确认号是累积的,表示该序号之前的所有数据均已正确接收。若中间有丢失,接收方会重复发送之前的ACK(如Ack=101),触发发送方重传。

    • 延迟确认

    开启后当收到全大小的分段(即MSS大小)时会等待下一个分段到来时一起发送ACK号,RFC 1122要求收到全大小分段时每两个分段发送一个ACK。如果第2个数据包一直没有到达会在延迟确认时间超时后发送ACK号。延迟确认的超时时间不能大于超时重传的超时间。在Linux上这个值在40ms到200ms之间。

    • 超时重传

    如果超过了指定时间还没有收到ACK,则认为数据丢失,并从最后收到ACK号开始重传所有后续的包。重传超时时间称为RTO,在Linux上这个值在200ms到120s之间。
    重传超时时间RTO是跟据RTT计算的,RTT是根据ACK到达时间算的,RTO一般是RTT的1到4倍,但始终在200ms至120s这个范围内。

    • 快速重传

    接收端如果收到乱序包就会认为发生了丢包,这时候每收到1个新的包就会发送一个相同的ACK(乱序前最后的ACK),这样发送端如果收到3个相同的ACK就会立即发送ACK指定序列号的分段。
    快速重传优点是一次只需要重传一个包,但是缺点也是只能重传一个包(如果丢包多的话)。

    在Reno算法中会利用快速重传机制进行快速恢复。

    • SACK

    SACK是一个扩展选项,SACK选项附带了丢失报文的超始序列号和结束序序号,一个SACK选项可以携带多组不连续的丢失报文边界。因为TCP可选选项的长度最大是40字节,所以一个TCP分段可以携带4个SACK区段的边界。

    • DSACK

    DSACK的选项格式也SACK一样,但DSACK描述的是收到的重复报文的区间,这样让发送者知道哪些报文发重了,从而调整发送策略。

    • PSH标志

    默认情况下TCP发送数据时尽可能使用大包而不是小包,连续的小包会一起在缓冲区中暂存,合并为一个大包一起发送出去。当使用PSH标志时带有PSH标志的分段分立即发送出去(包含当前分段前面未发送的数据)。接收方收到带有PSH的分段也会立即提交给应用层。
    PSH标志不会改变数据分段的发送顺序,URG标志则会改变数据分段的发送顺序。
    在Linux系统中当缓冲区没有后续数据时也会立即把数据发送出去并设置PSH标志。
    一般情况下发送数据量大时(开启Nagle算法且缓冲区满)就会执行包合并,如果数据量很小也会立即发送出去而没有包合并的机会,如果关闭Nagle算法则任何情况都不会执行包合并(网卡中靠硬件执行的LRO Offload除外)。
    设置PSH标志可以避免网卡执行LRO Offload(网卡有Bug除外)。
    关于数据的合并和发送规则可以参考Nagle算法。

    Views: 0

  • 关于TCP的序列号和确认号

    关于TCP的序列号和确认号

    TCP的序列号和确认号都是32位的正整数,其代表了数据在TCP数据流中的偏移字节位置。注意,这里序列号和确认号代表的是字节位置,在TCP概念中在TCP连接中传输的数据是字节流。数据在TCP层称为流(Stream),数据分组称为分段(Segment)。作为比较,数据在IP层称为Datagram,数据分组称为分片(Fragment),UDP 中分组称为Message。所以每个独立发送的TCP分组称为TCP Segment。
    现代网卡一般支持TSO和MRO,TSO把来自操作系统内核的小的TCP Segments合并为大的TCP Segments发送出去,MRO把从线路接收到的小的TCP Segments合并为大的TCP Segments提交给操系统内核,在网卡上执行合并和分片工作,减轻CPU的工作量。

    • 客户端发出的第一个Segment(SYN Segment),seq为client_isn,ack为0

    client_isn为初始化序列号(ISN),是随机生成的

    • 服务端发出的第一个Segment(SYN, ACK Segment),seq为server_isn,ack为client_isn+1

    server_isn为初始化序列号(ISN),是随机生成的,ack为client_isn+1

    对于后续的报文:
    客户端和服务器seq和ack是各自独立的,seq和ack的计算规则为:
    seq=last_send_seq+last_send_len
    ack=last_receive_seq+last_receive_len,这里没有考虑报文乱序和延迟确认的问题
    last_send_seq为上一次发送的TCP Segment序列号
    last_send_len为上一次发送的TCP载荷长度
    last_recive_seq为最后接收TCP Segment的seq
    last_receive_len为最后接收TCP Segment的载荷长度
    如果为ACK或FIN Segment载荷长度强制指定为1,其它情况按实际TCP载荷长度计算
    TCP载荷长度 = IP报文总长度 – IP头部长度 – TCP头部长度
    TCP Segment的Header Length字段是4个bit长度,每个单位代表4个字节,比如Header Length的值是5,则TCP Segment头长度就是20字节。

    Views: 0