传输层协议《TCP/IP详解 卷1:协议》学习笔记

本文主要面向实用,即不记录细枝末节(需要时应当查看准确的spec和impl),主要知道 TCP 传输的时候会干些什么从而影响到高层看到的性能变化,上层编程时做出应对或者定制UDP协议时要模仿 TCP 做什么。
前置复习,主要看后半部分:计网前四层总结


IP 层是 No Control 的

没有流量控制和差错控制, 一个原因是不同hop的router要频繁的解包和重新封装, 留控和差错控制降低效率. 反正网络层尽最大可能交付, 其他的在上层的传输层搞定不就好了.

而且下层的数据链路层已经有流控和差错控制了, 不必要添加太多冗余.

网络层只有IP头有Checksum, 检测网络层设备修改这个IP头MAC头TTL的时候的错误. 不检测数据包数据payload 的完整和正确性. 而且尽最大可能发送还会出现发不成功的情况.

所以传输层要负责检验自己的数据的错误和流量, 而且要使用, 传输层自己可能会由于各种问题导致给下层的数据就是错的. 如图是传输层做的 Error control.


UDP 基本

  • 无连接,基于数据包。
  • ipv4的校验可关闭(ipv6由于没有本身校验和,必须打开udp校验)。
  • 最大数据包长度是 IP 包决定的,IPv4 包最大 65536(由长度meta的大小决定的),所以udp payload最多是65507,ipv6 灵活一些。
  • 实际和路由器缓存有关,一般做到512就差不多了。(涉及ip包的路由器缓存支持)。
  • 然后历史遗留教训是 api 只给 payload,所以 ip 地址还要用系统去管理。离谱。
  • UDP可以做攻击,比如把src设定成victim,然后访问网络服务。最后网络服务就会回复victim而不是攻击者。(fraggle攻击)

TCP 基本 (tcp/ip第12章)

概念:
  • 字节流=>序号是基于字节的。
  • 和UDP一样,具有pseudo header 校验和(实际上层应该自己使用强校验)。
  • 对一个窗口(好多个IP包)只设定一个计时器。
  • 累积ACK的好处有节约包和丢ACK包的鲁棒。
  • TCP 是非对称连接(CS模式),全双工传输(双方都有各自的发送接受窗口)
  • TCP序列号只有32位,4gb寻址,但是实际可以循环用(locality)。
  • 第一个信息 SYN +随机序列号(什么 kernel 地址初值随机化)。
  • 纯 ACK 不会消耗序列号。
  • 四元组 == 套接字
  • MSS:根据以太网限制 1500 减去各header = 1460
三次握手 - 背诵:
  • Client: SYN + Seq = ISN 自己的序列号。
  • S: SYN + ACK, Seq, options,ACK Client 的序列号,Seq 自己的序列号。
  • C: ACK + Seq, options. ACK Server 的序列号,Seq 自己的序列号。
四次挥手 - 背诵 2:
  • C: FIN + ACK, Seq,(不说了,溜了溜了)
  • S: ACK, Seq(收到了,进入半关闭,我还没说完,你听我说完,注意,也可以没有这个!直接 FIN+ACK了)。
  • S: FIN + ACK, Seq (半关闭的结束,我说完了) (没收到 ACK 就持续轰炸FIN)
  • C: ACK, Seq (OK,再见 +2MSL(30-300s) 如果再收到 FIN,重发 ACK,我知道你说完了,难道你还不知道我知道你说完了?)
  • 2MSL之后才能重开。
  • 所以服务器他不能终止进程啊,一旦终止了,端口进入2MSL,完蛋了,直接网站瘫痪几分钟。我们后面会明白服务器怎么端口复用接受多个客户端连接的。
  • FIN_WAIT_2 无限等待问题:这个state没有 timeout,如果主动关闭方不允许半关闭,而对方又没有即时回复 FIN,比如服务器请求关闭连接,客户端由于在处理其他事情,或者客户端干脆终止进程没有释放资源(即没有底层网络栈发 FIN),导致无限等待。方法是做一个 timeout 。。。??什么鬼,一开始就设计 timeout 不就好了。。。
更多:
  • 同时打开(p2p打洞)和同时关闭问题(同时关闭不用进入半关闭),同时打开也很正常。。。(和两个连接的不同,那个端口号一共4个,这里就两个端口号),TCP设计成解析为同时打开为一个连接。
  • 随机序列号是为了防止短期冲突。RFC0793说可以直接全局变量4us +1,反正实际用起来都是 mod,也不怕爆范围。
  • 重开之后,之前延时的包可能会冲突,所以要避免重叠,这也解释了为什么实际上层还是会出现微小差错的情况,就是因为这些重叠,比如下游戏(一般用http下载,而其是tcp的)的时候。。。
  • NAT本身要检查校验和,所以他很有可能顺便检查了 TCP 状态,检测连接的开闭(P431)。(什么GC标记清除)
  • tcp 状态机(正经人谁记得住啊,所以我也不放图了,反正你(我)也不会看)。
  • 重启实际要静默一个MSL,防止延时包到达后认为是当前连接的(而且由于mod的存在,这个混淆是很有可能出现的)。
  • 对方非正常死亡的问题,半开连接,服务端不知道客户端消失了,连接仍然存在,或者客户端不知道服务端挂了,连接仍然存在。以服务器挂了为例,客户端会继续发包给服务端(认为服务端超时),这是服务端看不懂他这个是什么鬼,所以回了一个重置报文说我们已经焕然一新了,现在打扫干净屋子再请客,你请回吧!
  • timewait 2MSL 的时候可能收到一个报文,因为我们规定重置报文是直接 close 的,所以可能会导致提前结束 2MSL 引发错误,所以请 timewait 的时候只响应 FIN 而不包括重置报文。

TCP 端口复用

套接字概念

一个 TCP 连接是由套接字决定的:<src_ip, src_port>:<dst_ip, dst_port>

所以端口是可以复用的。

比如 ssh,一个 client 对 server 发多个请求,由于他们的 src_port 不一样,所以服务器会 treat them as different connections。
所以 TCP 底层必须支持 多路分解 demultiplexing.

服务器还要保留一条路做 listen 才行。

攻击

Dos 拒绝服务,由于资源被无效连接占用了。

SYN 泛洪攻击,伪造的源 ip 地址从而达到建立一堆假连接请求。然后一堆半打开,也没有三次握手成功。由于内存分配主要用来存储连接相关的 meta,但是实际上我们不需要马上分配这些资源,因为每次来的包里面都有这些信息,所以我们应该做的是回复一个精心设计的 序列号的 SYN+ACK ,这样就能在接受到一个 ACK 的时候去检查他是不是我曾经发过的 SYN+ACK,完全不用分配我的空间(SYN队列都不放他),等到真的确认之后才分配应用资源,SYN cookies。


TCP 超时重传

SACK(选择ACK):展示当前窗口乱序已接收区间信息:

在这里插入图片描述

RTO retransmission timeout 的决定 =》 测量 RTT(round-trip time)
  • 反馈控制理论
  • 经典低通滤波器(为什么等同于滤波器可以看 Karplus-Strong 弦乐器声音模拟算法的分析,里面讲了这个滤波器概念):短窗口平均
  • 标准统计:用多次测量的 mean devitation
  • RTO 初值 1s 则重传,SYN 超时3s 算超时,逐渐用 RTT 来反馈控制 RTO
  • 无时间戳:前面说了一个窗口只有一个计时器,所以一个窗口只能测一个 RTT
  • 有时间戳:在报文加上时间戳,各节点用减法就能求出每个包的 RTT,更好地统计
Karn 算法 超时后延迟一定时间再重传
  • 重传二义性,回复的不知道是哪个包 =》RTT 测不准
  • backoff factor 2指数退避系数,直到 ACK 最后一个重传序号才恢复 1.
  • 实际是通过降低发送速率(退避)来快速响应超时重传(配上拥塞控制)
快速重传
  • 接收到失序报文马上要 ACK 而不能 accumulate
  • 3 个 dup 马上重传而不是等计时器超时。(?这不是@see:拥塞控制的吗)
Sppurious retransmission
  • 判断超时错误:RTT变大,ACK 丢包
  • 通过反馈检测:扩展SACK包,传送收到的重复包信息
  • 发送方检测,并且停止重传,重新设定 RTO
包失序
  • IP 的原理:每个 IP 包(对应一个 TCP 包)是单独寻路的,涉及各级路由分布和链路畅通情况。
  • ACK 乱序:导致 TCP 发送方收到 dup ACK -》dupthresh = 3 的原因。
  • 发送方失序:(后包先到)dup ACK 导致快重传(TCP 无法判断)——》支持动态 dupthresh
链路层重传
  • IP 层不会重传,链路层可能引发重传(冲突避免,回退避让等),小概率出现重复包。
  • 但是 TCP 规定收到重复包也要发 ACK(因为这种情况可能是ACK丢失),声明重复了反馈给发送端调控发送,实际可能不是 TCP 层的锅。TCP 应当判断这种情况是谁的锅。
  • 使用 DSACK(dup-sack)避免乱序时 dup-ACK 引发重传(就是添加除了 range 信息,还添加 dup 信息在 ACK 包里)

TCP 窗口

ssh 性能分析:四个包一个键盘动作
  • 一个字符键入马上发一个 TCP 包
  • 服务端响应 ACK
  • 服务端回显 (或者捎带 +ACK)
  • 客户端响应 ACK
窗口
  • close,open,shrink 作为调控动作,区分 close 和 open
  • 每个 TCP 报文都有窗口信息,如果控制时窗口归零了(接收方流控了) 之后TCP会尝试 probe 窗口(发包问)
  • 实际流控后接收方可以发 ACK + open wnd ,但是这个丢包后就麻烦了,所以发送应该自己 probe(因为 ACK 能 dup 的原因只设定成接受到乱序包或超时)
  • sily window syndrome:对于接收端来讲,如果接收很慢,一次接收1个字节或者几个字节,这个时候接收端 缓冲区很快就会被填满,然后窗口通告为0字节,这个时候发送端停止发送,应用程序收上去1个字节后,发出窗口通告为1字节,发送方收到通告之后,发出1个字节的数据,这样周而复始,传输效率会非常低。同时如果发送端程序一次发送一个字节,虽然窗口足够大,但是发送仍是一个字节一个字节的传输,效率很低。
  • nagle 禁止小报文,同时接收方反馈 open wnd 时不能 open 小窗口(接收缓冲区释放到一定程度才开门)。
  • 缓存调优:接收方可能有大缓存,发送方(比如服务器)负载均衡只采用了小缓存(窗口)。所以缓存应当反馈浮动。明确窗口通告总是通告本方的接收窗口大小,只保证你继续发(超过窗口)的话就丢掉了。所以本方保持某个发送窗口的话,对方应当自己调控接受窗口。(因为窗口调控只是说接收方返回发送窗口而已,并且除了 0 open 不会请求让他扩大,只是通告我的接受窗口变大了而已)。
Nagle 算法
  • 窗口中非第一个小于 SMSS 的报文不能直接发出!(header 比内容还大)
  • 精妙:对于快速网络,ACK很快,所以小报文很快就会出现在窗口第一个,因此会马上被发出。而慢速网络,ACK很忙,尽量整合小报文再发送。
  • 但是开启 Nagle 后总的传输可能变慢,因为他强迫小报文等待。trade-off 在包的数量和总传输试验。
  • 问题在于:TCP 有延迟ACK!他直接把 Nagle 给做懵了(延时增加导致吞吐下降)。。。而 nagle 和 延迟 ack 都是为了利用带宽牺牲延时,反而由于延时负反馈带宽了属于是,选取方案应该看线路时延和带宽的情况,低时延低带宽开启 nagle + delay ack, 高时延低带宽关 delay ack 开 nagle,低时延高带宽根本不需要这些措施,高时延高带宽没想明白,调参很重要。。。
  • 游戏和远程桌面,ssh要关闭 nagle(API 使用 TCP_NODELAY 即可)

TCP keepalive

TCP 永久连接:只要不 close,中间不传输也不会断,就算路由器中间完蛋但是又恢复了又正常了。

Real world:nat 超时(@see: 只看 nat 部分),代理超时,防火墙关闭连接,应用程序超时,服务器判断超时,系统故障,重启。

比如 ssh 要用,然后如果为了能检测半连接(没有正常关闭的)及时释放资源,也可以用保活来probe。所以需要做保活(主要是为了 nat),但是为什么不然应用层做呢。。。(提供抽象封装dry了属于是)而且如果链路全部支持 tcp 本身的长连接(nat 路由器什么都支持),然后本来没有 data transmission,我甚至可以停路由器进行维修,不影响连接,但是由于保活的存在,笑死,反而把我连接 which 可以随着路由器恢复而恢复给干掉了。而且保活本身可以消耗流量, 占用资源(什么手机流量限量。。。)所以连规范都不规定了,爱做不做。。但是大家还是做了。

保活还有一个用处就是检测当前路由拓扑情况,或者探测网络情况,因为计时器是系统设定的,通过网关检测包保活包可以探测出流量情况,系统画像(这下数据挖掘了属于是)。
TCP 保活欺诈,先创建大量半连接,然后伪造保活包来浪费资源。
所以还是用应用层的吧。。。ssh 提供了应用层保活(我记得之前在 ssh config 里面设置过这个参数)。


TCP拥塞控制

见博客另一篇笔记,同时分析了实际现实世界中定制UDP的原因。
TCP拥塞控制

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值