OSI分层协议

TCP/IP协议分层

各层协议概述

tcp/ip协议族数据流

各层协议标识

  • IP地址:在网络层唯一确定一个具体的网络
  • 通过它找到某个子网
  • MAC地址:在链路层唯一确定一台主机。通过它找到子网内的某个主机
  • 端口号:在传输层唯一确定一个具体的应用,通过它找到主机内的某个应用
  • URI:在应用层唯一确定某个具体的资源,通过它找到应用内的某个资源

tcp/ip协议中数据转发

ARP地址解析协议

1.协议报文头格式

2.协议的作用

3.ARP高速缓存

ARP报文头格式

DST:目标MAC地址,ARP请求中固定填0xffffffffffff

SRC:源MAC地址,填写本机网卡MAC地址

长度或类型:对于ARP请求或应答固定为0x0806

硬件类型:物理链路硬件地址类型,以太网地址为1

协议类型:映射的协议地址类型,IPV4时值为0x0800

硬件大小:指出硬件地址的字节数

协议类型:指出协议地址的字节数

OP:指定是arp请求或应答以及rarp请求或应答

arp协议

  1. arp提供从网络层地址到硬件层地址的动态映射
  2. 会自动执行并且结果随时间更新
  3. 请求利用链路层广播询问
  4. 应答利用链路层单播应答
  5. arp协议利用arp高速缓存保障性能

arp高速缓存

3 IP逐跳协议

  1. IP协议报文头
  2. IP协议的作用
  3. IP协议的问题

Version:标识IP协议版本号,4bit最大值15。

IHL:IP首部长度,单位4字节。首部最大60字节

Total Length:IP首部和IP数据部分总长度,最大值65535

Identification:标识一个数据包,用于分片重组

Flags:标志是否可以分片,是否是某个包的最后一个分片

Fragment offset:某个分片位于原始报文中的偏移,重组报文时使用

TTL:分片生命周期

Protocol:上层协议标识(TCP/UDP/ICMP等)

校验和:针对IP首部的累加校验和

源IP:网络字节序的本机ip地址

目的IP:网络字节序的目标ip地址

字节序

整数的内存布局

IP地址划分

IP地址划分为网络号,子网号,主机号。早期的IP地址网络号与主机号使用固定分配

基于子网掩码的划分

子网掩码将ip地址中网络号的位设置为1,主机标识中的位设置为0

IP路由配置

在发送数据包时,首先确认IP包中的目的IP地址,再从路由控制表中找到与该地址具有相同网络地址的记录,将包转发给该记录对应的路由器。如果路由控制表中有多条相同网络地址的记录,利用贪心法选择最优匹配项,如果没有匹配项,转发到默认路由后再进行选路。例如:目标地址172.20.100.52

路由表记录:172.20/16 172.20.100/24

此时选择172.20.100/24对应的路由器

路由控制表

IP协议的问题

  • 点到点协议:IP数据包会经过IP选路时选中的每一个路由器的转发,任何一个路由器发生故障都会有问题
  • 面向无连接:IP发包前不需要建立连接,即使接收方不存在也会直接发包。
  • IP分片:链路不同,MTU也不同,IP会将数据包以路径MTU分片后发包,到达目的IP后重组,分片增加了出现问题的几率

4 ICMP协议

  1. ICMP协议报文头格式
  2. ICMP协议的作用
  3. ICMP协议的使用

ICMP报文头

类型:用于确定报文用途,比如回显应答报文类型为0。

代码:进一步区分报文用途

校验和:包含头部和数据部分的累加校验和

依赖于类型和代码的内容:针对不同代码和类型字段的组合并不相同,相当于用户数据

ICMP协议作用

  1. 端到端的协议,协议分成差错报文和查询报文。
    差错报文与IP结合使用,弥补了ip协议的不可靠问题以及定位错误的诊断信息。
    查询报文与IP结合使用,可以提供IP层的配置。
  2. ICMP通常由、IP层,TCP层甚至应用层触发执行。
  3. ICMP不为IP层提供可靠性,它反馈某些故障和配置信息,具体的可靠性保障由上层协议TCP处理。

ICMP的应用—ping程序

    Ping程序提供网络层到某台主机的路由是否可达

  1. 发送方组ICMP回显请求报文,标识符字段填写进程ID,序号字段从0开始,发送回显请求报文时序号递增,并在选项数据中保存发送的时间。
  2. 接受方按照客户报文组ICMP回显应答报文,原样回显该报文给客户端。
  3. 发送方接受到回显应答报文后,通过进程id判断是哪个进程,通过序号判断是否有乱序到达,多丢包现象,通过当前时间和记录的发送时间差判断ttl,并打印输出给进程id标识的进程

ICMP的应用--traceroute

Traceroute程序可以看到从源端主机到目的端主机经过的所有路由。

traceroute利用udp模块组成udp数据包,并将目的端口号设置为不可能的端口号,依次将IP数据报包头的ttl字段从1递增,traceroute依据返回的ICMP报文是端口不可达或请求超时来判断是否结束。

4 UDP协议

  1. 协议报文头格式
  2. 协议的问题

报文头格式

源端口号:16位网络字节序的本应用端口号,不期望对方回复时可不填

目的端口号:16位网络字节序的目的应用端口号,必填

长度:包括头部和数据的总长度,最大值65535

校验和:UDP头部,UDP数据,UDP伪头部的累加校验和

udp协议的问题

  • 面向无连接:即使对方不存在也会直接发送数据包,所有连接共用同一个缓冲区
  • 没有流控:在接收到用户数据的那一刻原样发送出去,接收方会被淹没
  • 没有拥塞控制:即使出现网络拥塞,仍然会发送数据包,造成网络瘫痪
  • 不可靠:出现丢包不会重发,无法处理数据包乱序到达的问题
“ 思考:如何利用不可靠的udp协议来实现一个可靠的,稳定的传输控制协议?

提示:

  1. 丢包
  2. 数据包乱序到达
  3. 流量控制
  4. 拥塞控制
  5. 接收方是否正常

5 TCP协议报文头

源端口:16位网络字节序的发送端应用端口号

目的端口:16位网络字节序的接收端应用端口号

序列号:从发送端到接收端数据流的一个字节偏移,该偏移代表包含该偏移值的报文段的第一个字节。

确认号:该确认号的发送方期待下一次接收的序列号

头部长度:以32位为单位的tcp报文头长度,最大值60字节

窗口大小:从接收方的确认号开始的窗口大小,也是tcp接受缓冲区的大小。

校验和:包含tcp头部,数据部以及伪头部的累加和

紧急指针:标志紧急数据结束的偏移值,当UGR置位时

紧急指针+序列号 = 紧急数据最后一个字节

选项:提供一些控制和高级特性,如利用MSS防止IP分片等

标志位

  1. syn:标志初始化链接的同步序列号,每条链接创建时第一条请求都需设置该标志
  2. fin:标志该报文段的发送方已经结束向对方发送消息
  3. rst:重置链接标志,通常由于链接异常导致
  4. psh:推送标志,接受到这个标志的请求,tcp应该立即将数据推送到应用程序,发送方清空缓冲区时会设置此标志
  5. ack:确认标志,设置了此标志,报文头中灰色字段才生效,一般每条用户数据都会设置此字段
  6. urg:紧急标志
  7. ece:ECN回显,通知发送方网络拥塞,需要启用拥塞避免算法
  8. cwr:拥塞窗口减小标志,通知接收方取消置位ece标志

三次握手

  • 选择ISN(initial sequence number):ISN每8ms递增1,新建一条链接增加64000,保证迷途的分组不会影响正常的tcp通信
  • 接收对方ISN:利用ISN追踪发送的每一个字节,ISN是tcp协议各种特性以及可靠性的基石
  • 协商MSS(maximum segment size),MSS是tcp的最大报文段长度,一般设置为MTU -tcp报文头长度 - ip报文头长度,避免ip对数据包分片影响性能

四次挥手

SO_REUSEADDR

执行主动关闭的一方将在TIME_WAIT状态等待2倍MSL的时间,防止最后的ACK丢失。并且可以让迷途的分组在该时间内自然消亡,不会影响以该套接字对建立的新链接。但这也导致该链接使用的本地端口在这段时间内不能被使用

该选项允许使用处于2MSL等待状态的本地端口

  • tcp是双工的链接,在底层针对每一条链接都有自己的发送缓冲区和接收缓冲区,同时可以互不影响的发送和接收数据
  • shutdown函数支持半关闭链接的功能,一方执行shutdown函数关闭写端,仍然可以接受来自对方的数据
  • close函数直接删除内核tcb结构(tcp control block)数据,针对执行了close的链接调用写方***接收到rst

半开链接

  • 通信双方任何一方机器故障将导致半开链接
  • 不向半开执行写操作永远无法发现半开链接
  • 大量的半开链接会导致无链接可用
  • 心跳机制可以检测半开链接

tcp的类型

  1. 交互数据流
  • 延迟要求高
  • 通常是小包
  • 降低吞吐量
  1. 成块数据流
  • 延迟要求不高
  • 包大小是MSS
  • 提高链接利用率

tcp确认报文

  • 收到请求立即确认
        响应时延低,对时延要求高的应用有好处
        影响链接利用率,可能造成网络拥塞
  • 一直等到有用户数据后确认
    将确认与用户数据一起发送提高链接吞吐量
    响应时延高,不利于时延要求高的应用
  • 设置过期时间,在超时或等到用户数据时确认,被tcp采用

Nagle

tcp默认开启Nagle算法

  1. 一条tcp链接最多只能有一个未被确认的未完成小分组(数据长度少于MSS),在该分组被确认前,不能发送其他分组
  2. 在该小分组的确认未到达时,收集后续的客户数据,在该分组的确认到达时以一个分组发送
  3. nagle与tcp延迟确认可以有效减少链接中的小分组,提高链接利用率

TCP_NODELAY

对于交互数据流的tcp链接,如ssh以及telnet等,开启nagle会影响用户感受,使用该选项关闭nagle算法

流量控制

tcp可以理解成双通的管道,流量控制负责控制对方的发送速度

tcp利用报文头中的窗口大小字段发出通告,对方发送的报文不能超过当前确认报文中确认号为基址,窗口大小作为长度的报文序号,超出这个范围的序列号将被以RST回复

注:发送方只能发送滑动窗口范围内的数据,接收方接收到滑动窗口范围之外的数据,以RST报文响应

滑动窗口

  • 窗口合拢:当发送数据时,窗口左边延向右滑动,窗口减小。
  • 窗口张开:当接收方消费接收缓冲区中的数据,并发送响应报文后,发送方将会看到窗口右边沿向右移动,窗口扩张。
  • 窗口收缩:快的发送方遇到慢的接收方时,为了提高链接利用率,当窗口小于MSS时通告窗口为0导致窗口收缩,RCF不建议此做法
  • 零窗口:当窗口左边延到达窗口右边沿时,通告窗口为0,通告窗口为0时,发送方不能发送数据,直到通告窗口不为0时。

窗口扩张通告

当接收方方通告窗口为0时,发送方停止发送数据,等待接收方通告窗口打开为止。

窗口扩张通告丢失?

  • tcp建立在不可靠的IP协议之上,任何一个tcp报文都可能丢失,包括窗口扩张通告
  • 发送方未收到窗口扩张通告,一直等待窗口扩张
  • 接收方在窗口扩张通告时确认了所有已到达数据
  • 接收方无法得知发送方后续是否还有数据需要发送
  • 此时双方可能会僵持住,通信无法继续下去

坚持定时器

接收方确认了发送方已发送的所有数据,并回复窗口大小不足以发送一个完整报文(通告窗口小于MSS)时,发送方设置指数退避定时器,定时器超时后发送窗口探查报文,窗口探查报文将会被持续重传,直到接收方窗口打开或关闭链接时为止,这个定时器被叫做坚持定时器。

拥塞窗口

  • 拥塞窗口用于控制发送方的发送频率
    拥塞窗口指出了从收到一个确认报文的时间内到下一个确认报文到达时,可以发送的报文字节数
  • 拥塞窗口随着确认报文在[1, 通告窗口]范围内动态变化
    当发生拥塞时,拥塞窗口减小,发送方降低发送频率,后随着确认报文持续增加拥塞窗口,直至达到通告窗口或下一次拥塞发生

慢启动

  • 当发送方一次发送多个报文段时,这些报文段经过慢速路由器时,可能会因为路由器缓冲不够而被丢弃,导致发送方重发后再被丢弃,严重影响利用率,甚至引发网络瘫痪
  • 慢启动将拥塞窗口设置为1,在接收到确认报文后,拥塞窗口以指数方式增长,直到拥塞窗口等于通告窗口或达到阀值为止

tcp吞吐量

带宽时延乘积

  • tcp吞吐量受制于拥塞窗口和通告窗口
    • 拥塞窗口受制于物理硬件的配置(不可变)
    • 通告窗口受制于接收方接收缓冲区大小(可变)

  • 增加接收方接收缓冲区以提高吞吐量
    • 带宽:物理网络单位时间内可以传送的数据量
    • 时延:发送数据到接收确认的时间间隔
    • 带宽时间乘积即是接收方缓冲区的最大值

糊涂窗口综合症

基于滑动窗口的流量控制方案,如果满足下列条件,会导致糊涂窗口综合症,导致链接利用率急速下降

  1. 快速的发送方与慢速的接收方
  2. 发送方发送少量数据 (少于MSS的报文段)
  3. 接收方通告一个小窗口(少于MSS的窗口)

解决方案

  • 接收方通告比当前窗口大的窗口时要满足
    • 窗口增加MSS大小
    • 窗口增加接收缓冲区一半大小

  • 发送方发送数据时需要满足
    • 可以发送满长度报文(MSS大小)
    • 可以发送接收方通告窗口一半大小的报文
    • 当前链接没有未被确认的数据时可以发送任何数据(Nagle)
    • 当前链接禁用nagle算法时

超时重传

  1. Tcp发送端计算基于时间变化的rtt测量值
  2. 根据rtt测量值设置rto
  3. 在发送报文时记录报文序列号并设置定时器
  4. 收到记录报文序列号的响应时取消定时器
  5. 在定时器到期时未收到该序列号的确认时重传该报文,调整拥塞窗口并增大rto的退避因子

思考:这里定时器是每个发送报文都会设置么,为什么?

快速重传

  • 接收端按序接收报文,当收到一个失序报文段时,需要产生一个重复的确认报文,这个确认报文不该被延迟
  • 发送端收到重复的确认报文时,无法判断重复确认是因为报文乱序到达还是报文丢失,因此等待少量重复的确认报文到来
  • 发送端连续收到3个或三个以上重复的确认报文时,即认为被重复确认的报文丢失,立即重传而不等待rto定时器的超时
  • 发送端不需要等待被重传报文的确认即可开始传输后面的报文

网络拥塞

  • 某个已发送数据的rto定时器超时需要减少进入链路的数据
    • 硬件保证由于分组损坏导致的丢失极少
    • 中间路由缓存有限,当大量数据进入某个中间路由导致缓存耗尽,中间路由将丢弃分组,且不会发送ICMP给源主机

  • 连续三次重复的确认需要以恒定速率发送数据包
    • 当有错乱分组到达时不应延迟确认需要及时回复重复确认
    • 收到一个重复确认意味着一个数据包到达目的主机

rto超时的拥塞避免

  • 初始值:cwnd = 1 ,ssthresh = 65535
  • 超时时:ssthresh = (cwnd与rwnd取最小值/2)但是不小于2MSS,cwnd = 1
  • 重发报文后:收到确认cwnd指数增长,直到cwnd=ssthresh
  • cwnd = ssthresh时:收到一个确认后cwnd增长 MSS的值

重复确认的拥塞避免

  • 初始值:cwnd = 1 ,ssthresh = 65535
  • 三次重复确认时:ssthresh = cwnd/2 cwnd = cwnd + 3 * MSS
  • 每次收到一个重复确认时:cwnd += MSS
  • 当收到新的确认时,cwnd = ssthresh,

TCP常见异常

  1. 应用崩溃
  2. 机器崩溃
  3. 机器崩溃后重启
  4. 网络断开
  5. 大量半开链接
  6. 大量半关链接

应用崩溃

应用崩溃时,系统会自动关闭已打开文件描述符(套接字本质也是文件描述符),这将导致内核tcp模块发送fin报文并删除该链接的tcb

另一端read该套接字时,将会返回EOF文件结束标志,由此得知对端状态变更。

另一端write该套接字时将会被响应一个rst报文,再次写入时触发sigpipe信号(信号默认动作是结束进程,即使捕捉该异常,write也会得到sigpipe错误)由此也可得知对端状态变更

另一端读或写都可以得到对方的异常状态

机器崩溃

机器崩溃时,tcp内核模块无法做出反应,对端不会接收到任何通知也不会再接收到任何数据

另一端read该套接字时,将会被挂起或得到EAGAIN错误

另一端write该套接字时将会持续重传,直到tcp放弃重传才会返回错误

如果另一端不主动写入,永远无法发现对端异常

机器崩溃并重启

机器重启后,该链接丢失,内核不会为该链接重新建立tcb数据,因此当收到该链接的数据包时,内核将响应rst报文

另一端read该套接字时,将会被挂起或得到EAGAIN错误。

另一端write该套接字时将会被响应一个rst报文,再次写入时触发sigpipe信号(信号默认动作是结束进程,即使捕捉该异常,write也会得到sigpipe错误)由此也可得知对端状态变更

如果另一端不主动写入,永远无法发现对端异常

网络断开

网络断开时,数据无法发送到对方,正常的数据通信和触发关闭链接的报文都被抑制

另一端read该套接字时,将会被挂起或得到EAGAIN错误

另一端write该套接字时将会持续重传,直到tcp放弃重传才会返回错误

如果不主动写入,两端都无法发现对端异常

大量半开链接

半开链接是指未能触发正常关闭链接的步骤,通信的一段就把内核为该链接维护的tcb模块删掉的链接

半开链接占用系统和进程的文件描述符,严重时导致无描述符可用。

系统崩溃,系统崩溃后重启,网络断开时都会导致半开链接,使用心跳机制可以处理类似的链接

大量半关链接

半关链接是tcp终止序列中一端执行了关闭,另一端未执行关闭时的状态,主动执行关闭的一段将停留在FIN_WAIT_2状态,另一端将停留在TIME_WAIT状态,半关链接大量积累,也会导致系统或进程无文件描述符可用

当一端使用了shutdown关闭了写端,另一端未执行shutdown关闭写端,并且没有使用close关闭整个链接会导致半关链接,需要在收到对端发送的FIN报文之后,及时关闭链接

Tcp协议总结

tcp的可靠性基于对发送数据按字节排序,并将发送数据暂存在发送缓冲区中,直到收到来自对方的对应确认报文后才会删除,如果期望的确认没有如期到达,就进行重发并再次等待,直到达到tcp的最大重发次数后放弃,因此tcp的可靠并不是指数据一定能发送到接收方,而是指数据要么发送到对方,要么可靠通知发送方数据未送达。

如果tcp每发一个报文就等待对方的确认,在一个rtt时间内只有一个报文交换,网络利用率过低,因此设计滑动窗口机制提高性能

为每条tcp链接设计一个接收缓冲区,即使当有报文丢失或乱序到达,只要消息号在窗口范围内,就暂存乱序到达的后续消息,重复确认处于空洞中的报文序号,等待缺失消息到达后推送给应用。

当每条链接在一个rtt之内都发送滑动窗口对应的报文时,在一些慢速链路中极易造成网络拥塞,中间路由器开始丢弃报文,发送端定时器超时,对报文进行重发后会加剧问题,甚至引发网络瘫痪

因此利用拥塞窗口控制本方发送频率,利用慢启动,拥塞避免,快速恢复等算法来尽量减少网络拥塞的发生,进一步提高网络利用率