车载以太网相关知识记录
- VHR相关知识点
- 以太网知识全解
- T1物理层相关规范与测试内容
- 以太网帧大小规范
- IP相关知识
- 网络指令集&使用实例
- 本地链路地址(也称为链路本地地址,Link-Local Address)的启用时机
- 本地链路地址分配ARP过程时间参数
- IPV4相关知识点
- TCP相关知识点
- TCP拥塞处理机制
- 流量控制
- 窗口关闭的问题
- 糊涂窗口综合症
- 拥塞控制
- 重发类型与处理方式
- 相关问题汇总(问答式)
- 为什么会发RST报文
- 零窗口控制报文ACK响应报文结构&处理机制
- 检测接收窗口状态:
- 防止死循环:
- TCP零窗口探测的实现方式
- 零窗口探测报文格式
- 当处于CLOSED状态时候对请求的处理方式
- TCP 状态机各种状态如何识别
- 如何检测TCP连接进入CLOSED状态
- 关于Stream of full-sized segments 满大小数据段的ACK响应机制
- 关于全尽寸的数据流的确认机制:每第二个流需要确认
- 如何确认当前状态为【TIME_WAIT】
- 针对已经建立连接,重复发起连接请求情况
- RST重置报文段的SEQ如何设置
- 维活报文格式&应用
- 零窗口声明&零窗口通报
- TCP 窗口更新声明
- TCP状态机各状态如果识别与确认
- 何时以何种格式发送RST重置报文段
- 哪些阶段应用层的读取调用可以返回数据至应用层
- ACK挑战报文段格式与发送时机
- 如何判断总线出现拥塞
- ARP基本应用场景
- ARP相关知识点记录
- CAPL网络脚本设计
- VLAN TC2测试相关内容与知识点
- 最小报文数:假设每个报文都是最小帧大小(64字节),则每秒能传输的报文数为: 每秒报文数(最小)= 64 字节×8 位/字节 100 Mbps
- 最大报文数:假设每个报文都是最大帧大小(1500字节),则每秒能传输的报文数为: 每秒报文数(最大)= 1500 字节×8 位/字节 100 Mbps
- ICMP相关知识点
- ICMP报文分类:差错控制报文&查询报文
- ICMP协议
- ICMPv4 InternetControl Message Protocol Version 4
- ICMP不会响应的场景
- ICMP报文包括以下类型
- 每种差错报文&查询报文类型报文结构
- DHCP动态主机配置协议
- DHCP地址分配类型
- DHCP消息格式
- 各字段填充要求
- magic Cookie字段意义
- DHCP服务器配置界面
- IP地址获取失败处理方式
- DHCP 如何分配地址(消息交互流程)
- DHCP状态机
- DHCP&BOOTP区别
- DHCP作用及特点
- DHCP服务器IP分配三种方式
- DHCP协议报文类型
- DHCP客户端重用曾经使用过的地址的工作原理(重启等场景)
- DHCP客户端更新租期示意图
- 填充选项&结束选项域名Code=1
- 子网掩码
- 时间偏移域名Code=2
- 路由器选项实际即为网关的IP地址域名Code=3
- 时间服务器选项域名Code=4
- 域名服务器选项域名Code=6
- 日志服务器选项域名Code=7
- Cookie 服务器选项域名Code=8
- LPR 服务器选项域名Code=9
- Impress服务器选项域名Code=10
- 资源位置服务器选项域名Code=11
- 主机名选项域名Code=12
- 启动文件大小选项域名Code=13
- 优点转储文件域名Code=14
- 域名Code=15
- 交换服务器Code=16
- 根路径Code=17
- 最大数据报重组大小根路径Code=22
- 默认 IP 生存时间Code=23
- 路径 MTU 老化超时选项
- 广播地址选项
- 执行掩码发现选项
- TCP 保活间隔选项
- TCP Keepalive 垃圾选项
- 请求的 IP 地址
- IP地址租用时间
- 选项过载
- DHCP 消息类型
- 服务器标识符
- 参数请求列表
- 消息
- 最大 DHCP 消息大小
- 续订 (T1) 时间值
- 新绑定 (T2) 时间值
- 厂商类别标识符
- 客户标识符
- 网络时间协议服务器选项
- 交换机工作原理
- 二层交换机的优点和缺点
- 三层交换机
- TLS规范&问题汇总(基于CANOE的开发过程)
- CAPL实现TLS过程
- NTP协议原理与实现
- SOMEIP协议规范与测试规范
VHR相关知识点
https://mp.weixin.qq.com/s/xnCmp-Y-qqvsPBYMBH7b4A
以太网知识全解
T1物理层相关规范与测试内容
https://blog.csdn.net/Dotrust2013/article/details/136938683物理层测试概念
为什么要分主从
工业PHY是不需要指定PHY的master/slave角色的,两个PHY可以自己协商确定角色。但是在汽车PHY中,角色需要静态配置,一个PHY事先设定为slave,另一个为master,这么做的主要目的是减小link up的时间,因为汽车对启动时间有要求。
两个千兆电口对接时,一端要工作在master模式,另一端则工作在slave模式。Slave一端不使用自己的时钟,而是从接收到的信号中恢复时钟,自己发送信号时就使用恢复出来的时钟。这样,可以有效保证双方的同步。为了提高链路建立的速度,主、从属性必须预先配置,不能自动协商。
编码技术
假设我们使用的是MII接口,通信速率是100Mb,数据宽度是4bit,速率是25M。为了匹配25MHz * 4bit = 100Mbit/s的速率,PHY从MII接口收到数据后,会首先进行一个4B3B的转换,并将时钟频率提高到33.33333MHz,以保持100 Mbps的位速率。
之后PHY要再进行3B2T的操作,将每次接收到的3个bit转化为2个三进制电平值(取值范围是-1,0,1),具体的对应关系如上图中的表所示。3个bit有8种组合(即2的三次方),两个电平值有9种组成(即3的平方),所以后者可以覆盖前者。此时时钟周期仍然是33.333M,但是每个时钟周期中的两个电平就能够表示3个 bit了,所以此时的数据速率仍然是100Mbit/s,每个电平实际上包含了1.5bit信息。3B2T的转换关系如下表
;
不同的 Type 字段值可以用来区分两种帧类型:
当 Type 字段值≤1500 时,帧使用的是 IEEE 802.3 格式(因为该格式的改字段表示的是帧长度,而以太网帧 MTU 值为 1500);
当Type 字段值≥1536 时,帧使用的是 Ethernet II 格式。
FCS:Checksum校验和,占用 4 Byte,校验不通过,则该帧被认为传输不完整或遭到篡改,将直接丢弃处理。
MTU
MTU(Maximum Transmission Unit,最大传输单元),属于数据链路层的概念,用于在数据链路层对数据帧长度进行限制,是指网络能够传输的最大数据包大小,以字节 Byte 为单位。以太网帧的默认 MTU 值为 1500.
基于对网络时延、传输效率等因素的综合考虑,不同链路介质类型的网络有不同的默认 MTU 值,以下是一些常见网络的默认值:
IP相关知识
第 2 层广播是目标 MAC 地址为的帧为FFFF.FFFF.FFFF。
这是专门为广播帧保留的 MAC 地址,它有时也显示为ff:ff:ff:ff:ff:ff或ff-ff-ff-ff-ff-ff这些都是显示“所有 F 的”MAC 地址的相同方式。
任何网络上的任何节点都可以简单地使用此目标 MAC 地址创建 L2 标头,以便将帧发送给本地网络上的每个人。
交换机知道,如果他们看到这个目标 MAC 地址,他们应该自动将帧溢出所有接口(接收帧的接口除外)。
请记住,设置目标 MAC 地址的是帧的发送方,因此,帧的发送者决定了将特定帧传递给本地网络上的每个人还是传递给网络上的单个节点。
本地广播&定向广播
本地广播 IP地址是:255.255.255.255
无论特定主机位于何种 IP 网络上,该主机始终可以使用该 IP 地址向本地网络上的每个节点发送数据包。
在我们的拓扑中,主机 1 可以向 IP 地址发送一条消息,以便255.255.255.255与其本地网络上的其他人通话。
请注意,这也包括路由器,由于 R1 在10.1.1.0/24网络中有一个 IP 地址,因此它是主机 1 的本地网络的成员。这个广播对应MAC也为L2地址即全FF,但是不会被路由,即只能在本地网络传播
定向广播 IP 地址
就是所谓的每个子网的广播 IP,要找到这个 IP 地址,您必须进行一些子网划分。
与上述本地广播非常相似,任何主机都可以使用定向广播 IP 与其本地网络上的每个主机通话。
主机 1 具有网络10.1.1.11上的 IP 地址10.1.1.0/24,因此,此 IP 子网的广播 IP 地址为10.1.1.255。
主机 1 可以使用此 IP 地址向其本地网络上的其他所有人发送消息,就像上面的本地广播一样:
每个 IP 网络都有自己的广播 IP。因此,主机可以使用外部网络的广播 IP 地址将广播定向到该外部网络中的每个节点,因此,术语定向广播(或有时有针对性的广播)。
在我们的拓扑中,主机 1 可以使用 IP 地址与网络10.3.3.127中的每台主机10.3.3.0/25通信:
图片
Host1# ping 10.3.3.127
PING 10.3.3.127 (10.3.3.127): 56 data bytes
64 bytes from 10.2.3.3: seq=0 ttl=253 time=1.171 ms
64 bytes from 10.3.3.66: seq=0 ttl=61 time=3.683 ms (DUP!)
64 bytes from 10.3.3.55: seq=0 ttl=61 time=7.340 ms (DUP!)
64 bytes from 10.3.3.44: seq=0 ttl=61 time=9.838 ms (DUP!)
--- 10.3.3.127 ping statistics ---
1 packets transmitted, 1 packets received, 3 duplicates, 0% packet loss
round-trip min/avg/max = 1.171/5.508/9.838 ms
有线广播
如果一个IP地址的二进制数都是1,那你就会得到255.255.255.255这个IP地址。
所以,255.255.255.255作为IPv4中最大的数字,它就被定义为“整个互联网”。如果0.0.0.0代表啥都不是,255.255.255.255就代表我啥都有。
255.255.255.255作为特殊的IP地址,属于有线广播。它不被路由,反而会被送到相同物理网络段上的所有主机中去,所以也被很多人称为“广播”功能。
啥东西找不到了,咱们就通过“广播”嚎一嗓子,是不是最快找到东西的办法?DHCP给设备配置IP地址也是这么个道理。
所以,我们现在就能绕回来说DHCP和0.0.0.0还有255.255.255.255这三者的关系了。这样,你也就明白这俩IP地址最简单的用途。
IP地址0.0.0.0
####对服务器(本机)而言
当socket绑定的IP地址0.0.0.0时, 表示监听本机上的所有IP地址, 也就是接收本机所有网卡发到本进程端口的请求。
如果一个主机有两个IP地址,它们分别是192.168.250.250 和10.128.100.100,并且该主机上的一个nginx服务监听的地址是0.0.0.0和端口 8069,那么通过这两个ip地址:8069都能够访问该服务。
如果有多个IP地址的时候,如果涉及发送的话,需要bind一个特定的IP才能完成发送操作
对网络(路由)而言
0.0.0.0表示整个网络中的所有主机,当数据包在路由器之间转发时, 在路由表中如果找不到目的IP所在的网段, 就会发到目标IP为0.0.0.0的网关处,也就是0.0.0.0表示的是默认路由。
C:\Users\QIYOU>route print
IPv4 路由表
===========================================================================
活动路由:
网络目标 网络掩码 网关 接口 跃点数
0.0.0.0 0.0.0.0 10.129.10.254 10.129.10.43 35
10.129.10.0 255.255.255.0 在链路上 10.129.10.43 291
10.129.10.43 255.255.255.255 在链路上 10.129.10.43 291
10.129.10.255 255.255.255.255 在链路上 10.129.10.43 291
127.0.0.0 255.0.0.0 在链路上 127.0.0.1 331
127.0.0.1 255.255.255.255 在链路上 127.0.0.1 331
127.255.255.255 255.255.255.255 在链路上 127.0.0.1 331
192.168.19.0 255.255.255.0 在链路上 192.168.19.1 291
192.168.19.1 255.255.255.255 在链路上 192.168.19.1 291
192.168.19.255 255.255.255.255 在链路上 192.168.19.1 291
192.168.56.0 255.255.255.0 在链路上 192.168.56.1 281
192.168.56.1 255.255.255.255 在链路上 192.168.56.1 281
192.168.56.255 255.255.255.255 在链路上 192.168.56.1 281
192.168.137.0 255.255.255.0 在链路上 192.168.137.1 281
192.168.137.1 255.255.255.255 在链路上 192.168.137.1 281
192.168.137.255 255.255.255.255 在链路上 192.168.137.1 281
192.168.145.0 255.255.255.0 在链路上 192.168.145.1 291
192.168.145.1 255.255.255.255 在链路上 192.168.145.1 291
192.168.145.255 255.255.255.255 在链路上 192.168.145.1 291
224.0.0.0 240.0.0.0 在链路上 127.0.0.1 331
224.0.0.0 240.0.0.0 在链路上 10.129.10.43 291
224.0.0.0 240.0.0.0 在链路上 192.168.137.1 281
224.0.0.0 240.0.0.0 在链路上 192.168.56.1 281
224.0.0.0 240.0.0.0 在链路上 192.168.19.1 291
224.0.0.0 240.0.0.0 在链路上 192.168.145.1 291
255.255.255.255 255.255.255.255 在链路上 127.0.0.1 331
255.255.255.255 255.255.255.255 在链路上 10.129.10.43 291
255.255.255.255 255.255.255.255 在链路上 192.168.137.1 281
255.255.255.255 255.255.255.255 在链路上 192.168.56.1 281
255.255.255.255 255.255.255.255 在链路上 192.168.19.1 291
255.255.255.255 255.255.255.255 在链路上 192.168.145.1 291
===========================================================================
有限广播地址255.255.255.255
如果一个IP地址的网络号和主机号全为1,也就是255.255.255.255,这代表本网广播,所以也称受限广播地址,又称本地广播地址。也就是向本网络上所有主机广播信息,本网络上所有主机都会收到。路由器阻挡该分组通过,将其广播限制在本网内部。
它的作用是通常计算机启动时,希望从网络IP地址服务器DHCP处获得一个IP地址。
定向广播地址192.168.250.255
如果一个IP地址只有主机号是全1,代表的是在某网段内的定向广播,也叫广播地址,比如192.168.250.255,这是一个C类地址,最后的255是全1主机号,这就代表只在192.168.250.0这个网段上广播;再比如172.16.255.255,这是一个B类地址,最后的255.255是全1主机号,这就代表在172.16.0.0这个网段上广播。
路由器在目标网络处将IP直接广播地址映射为物理网络的广播地址,以太网的广播地址为6个字节的全“1”二进制位,即:**ff:ff:ff:ff:ff:ff **
回环地址127.0.0.1
这个主要用于测试本机协议配置是否正确。
用汉语表示,就是我自己。在Windows系统中,这个地址有一个别名Localhost。寻址这样一个地址,是不能把它发到网络接口的。除非出错,否则在传输介质上永远不应该出现目的地址为127.0.0.1的数据包。
组播地址224.0.0.1
从224.0.0.0到239.255.255.255都是组播地址的范围。
组播指有确定的源和加入了组播组的特定的设备,信息源与特定接收者之间一对多的通信。
常用组播地址如下:
224.0.0.0 是保留地址
224.0.0.1指所有主机与路由器
224.0.0.2指所有组播路由器
224.0.0.5指用于OSPF发送路由信息
224.0.0.6指用于OSPF选举DR
224.0.0.9 指运行RIPv2路由协议的路由器
224.0.0.10指用于EIGRP
224.0.0.11指移动IP中的移动代理
224.0.0.12指用于DHCP中继
224.0.0.13指用于PIMv2路由器
224.0.0.18指用于VRRP
224.0.0.22指开启IGMPv3的路由器
224.0.0.25指表示所有的交换机
224.0.0.251指路由协议预留地址
224.0.0.252指路由协议预留地址
与广播地址的区别是他们传递的范围不相同,相同组播地址的都会接收,不同组播地址的就不会接收,主要看组播地址是否一致。
组播的MAC生成
V4组播的MAC地址供48位
协议规定,V4组播MAC地址的高24位为0X01005E,第25位为0,低23位为IPv4组播地址的低23位,IPV4组播地址与MAC地址的映射关系如下图所示。
即三个字节为0x01005E + 后三个字节直接映射IP的后23位
组播IP划分
- 224.0.0.0~224.0.0.255 为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
224.0.1.0~224.0.1.255 是公用组播地址,可以用于Internet;欲使用需申请。
224.0.2.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效;
组播mac地址(组播IP地址映射而来)
前25bit固定不变01005e0
后23bit直接由组播IP地址后23位映射而来
例如组播组地址224.0.1.1对应的组播MAC地址为01-00-5e-00-01-01。
一个组播mac地址会对应32个组播IP地址
IPv4组播地址的前4位是固定的1110,对应组播MAC地址的高25位,后28位中只有23位被映射到MAC地址,因此丢失了5位的地址信息,直接结果是有32个IPv4组播地址映射到同一MAC地址上。例如IP地址为224.0.1.1、224.128.1.1、225.0.1.1、239.128.1.1等组播组的组播MAC地址都为01-00-5e-00-01-01。网络管理员在分配地址时必须考虑这种情况
网络指令集&使用实例
本地链路地址(也称为链路本地地址,Link-Local Address)的启用时机
主要依赖于网络协议(如IPv4或IPv6)以及具体的网络环境和配置。以下是对IPv4和IPv6中本地链路地址启用时机的详细分析:
IPv4中的本地链路地址(也称为APIPA地址)
自动启用:
在IPv4中,当网络接口无法从外部(如DHCP服务器)获取到有状态的IP地址时,主机会自动在169.254.0.0/16范围内随机选择一个地址(除两端的地址用作保留),并进行冲突地址检测(ACD)。一旦找到一个不冲突的随机地址,该地址就会被用作本地链路地址。
这种自动分配机制被称为自动专用IP寻址(APIPA),它允许设备在没有DHCP服务或其他地址配置方法的情况下,自我配置一个可用的IP地址。
配置条件:
主机在启动时会检查其网络接口是否已配置有有效的IP地址。
如果没有,且无法从外部源(如DHCP服务器)获取地址,则会自动启用APIPA地址。
本地链路地址分配ARP过程时间参数
在本地链路地址(特别是IPv4链路本地地址,即169.254/16地址块)的分配和冲突处理过程中,ANNOUNCE_WAIT、ANNOUNCE_INTERVAL和DEFEND_INTERVAL是三个重要的时间参数。以下是对这些参数的详细解释:
1. ANNOUNCE_WAIT
定义:
ANNOUNCE_WAIT是设备在发送完ARP探测包后,等待ARP回应的延时时间。在这个时间段内,设备会等待网络中其他设备对探测包的回应,以判断所选择的IP地址是否已被占用。
作用:
确保设备有足够的时间来接收并处理其他设备对ARP探测包的回应。
减少因网络延迟或冲突而导致的地址配置错误。
默认值:
根据RFC 3927等标准文档,ANNOUNCE_WAIT的默认值通常为2秒。
2. ANNOUNCE_INTERVAL
定义:
ANNOUNCE_INTERVAL是设备在发送多个公告(Announce)包时,相邻两个公告包之间的时间间隔。这些公告包用于向网络中的其他设备宣告设备已占用的IP地址。
作用:
确保网络中的其他设备能够接收到设备宣告的IP地址信息。
减少因公告包发送过于频繁而导致的网络拥塞。
默认值:
同样根据RFC 3927等标准文档,ANNOUNCE_INTERVAL的默认值也通常为2秒。此外,公告包的数量(ANNOUNCE_NUM)一般也有规定,如发送两个公告包。
3. DEFEND_INTERVAL
定义:
DEFEND_INTERVAL是设备在地址探测时未发现冲突,但在地址绑定后(即设备开始使用该地址进行通信后)发现冲突时,重复发送ARP包以确认冲突情况的时间间隔。
作用:
在地址绑定后,为设备提供一段时间来检测和响应地址冲突。
如果在DEFEND_INTERVAL时间内多次检测到冲突,则设备会重新配置一个新的链路本地地址。
默认值:
根据RFC 3927等标准文档,DEFEND_INTERVAL的默认值通常为10秒。这个值允许设备在发现冲突后有足够的时间来重新配置地址,同时避免了因频繁更换地址而导致的网络不稳定。
总结
这三个时间参数在本地链路地址的分配和冲突处理过程中起着关键作用。它们共同确保了设备能够高效地配置和使用链路本地地址,同时减少了因地址冲突而导致的网络问题。在实际应用中,这些参数的默认值通常足以满足大多数网络环境的需求,但在特定情况下也可以根据需要进行调整。
IPV4相关知识点
QOS(TOS)解读
DS=defferentiated Services Codepoint(服务区分代码点)占用TOS的高6位 CU位不使用的二个位值
PHB(Per-Hop Behavior每一跳行为)是一种在网络中定义每个节点(或每一跳)对数据包进行处理的规范或策略。PHB定义了一个数据包在通过网络的每个节点时应该接受的处理方式,包括转发、排队、丢弃等。PHB的目标是为网络服务提供一致性的行为,确保在整个网络中维持特定的服务质量水平。
不同的PHB对应于不同的服务质量类别,它们通过使用Differentiated Services Codepoint(DSCP)字段来进行标识。DSCP是包含在IP头部的一个字段,它指定了数据包的服务质量要求,并由网络设备用来确定每个数据包在网络中的处理方式。
标准化的PHB
EF(Expedited Forwarding):提供低延迟和低抖动的服务,通常用于实时应用如VoIP(Voice over IP)。DSCP值为 0b101110(DEC:46)。只有一个固定值46
BE PHB(默认PHB)
BE(Best Effort)是一种Per-Hop Behavior(PHB),通常被用于标识网络中对普通数据传输的默认处理方式。BE PHB并不提供特殊的服务质量保
证,而是采取“尽最大努力”的方式传输数据,适用于那些不对延迟、抖动或带宽有特别要求的普通应用。
AF(Assured Forwarding):分为四个类别,每个类别都有不同的优先级和容忍丢包的程度,以提供不同的服务等级。AF PHB分为四个类别:AF11、AF12、AF13、AF21、AF22、AF23、AF31、AF32、AF33、AF41、AF42 和 AF43。每个类别都有不同的DSCP编码。例如,AF31的DSCP值为0b011010。(Amn m为DSCP除8的商 n为余数)
排队:
AF PHB引入了排队机制,其中有四个不同的类别(Class),每个类别都会被放置在不同的队列中。
每个类别内部还有一个丢包概率。当队列已满时,具有“高丢包”概率的数据包将在其他数据包之前从队列中删除。
拥塞避免:
AF PHB设计用于帮助避免网络拥塞。通过排队和管理丢包的方式,它能够在网络负载增加时提供更可靠的服务。
如下图所示,AF PHB 共有四个类别,分别是AF1、AF2、AF3、AF4,用于放置到不同的队列中。每个类别内部有三种不同的丢包概率,因此总共有12个AF(AF11、AF12、AF13、AF21、AF22、AF23、AF31、AF32、AF33、AF41、AF42 和 AF43)。
BE(Best Effort):默认的服务类别,提供基本的数据传输服务,不保证特定的服务质量。BE PHB的DSCP值通常为0b000000。
EF(Expedited Forwarding PHB)通常用DSCP值“EF”来标识,在二进制中表示为101110。EF PHB也有两个主要功能:
排队:
EF PHB的目标是将数据包放入一个队列,以便它们经历最小的延迟和数据包丢失。用于实时应用程序的数据包(如实时视频流)所在的位置。
为了实现这一目标,我们使用了一种称为优先级队列的机制。只要优先级队列中有数据包,它们将在所有其他队列之前被发送。然而,
这也带来了一定的风险,即其他队列可能无法发送其数据包,因此我们需要为此队列设置一个“速率限制”。这通过一种称为policing的
机制来实现。
流量监控:
为了防止EF队列过于占用网络资源,需要对其进行速率限制。Policing用于强制执行这种速率限制,确保EF队列不会过分占用带宽,从而保证其
他队列有机会发送其数据包。
CS PHB
新的DC字段引入了一个问题,因为在旧设备中仍在使用TOS字段的IP优先级。为了向下兼容,因此定义了CS(class selector)PHB。如下图所示,CS字段和IP优先级是一样的。Cm(表示优先级 DSCP值能够被8整除 m=dchp/8的商值)
IPV4选项内容
实际报文格式:
参数有Pointer:从索引号1开始计数,时间戳的pointer的参数为5 路由指定的Pointer从4开始 length参数为整个参数的长度(即整个选项的全部字节数量),且整个选项字节数量不能超40个
IPV4的重组与分片
分片偏移数据值
为8字节的倍数,所以每个传送数据的时间应该以8字节对齐因为总长度是16位长度,而偏移补FLAGS占用3位,故偏移8字节对齐才能与总线度大小匹配上,故数据传送的时候,需要保证非最后一帧数据,要8字节对齐
分片重组的依据
- 重建数据报依据:IPV4的identification, source, destination, and protocol.四个域值相同的时候才会重组。有任何一个不同将无法重组数据报
分片原因与依据
因为Ethernet链路对每次传送的包有大小限制即MTU,如果从传输层传递包的UDP包或是TCP包大于MTU的大小,那么将会进行分片传输,并在对端的TP即传输层完成包的重组,重组完成后才会传送传输层使用。
分片的执行方&重组执行方
- IPV4的分片,可以在发送方主机,也可以在数据传输路径上路由器来完成
- 只能在数据到达目标端,由目标端完成重组操作
- 每个分片传输的路径可能不一致
- 减轻中间路由设备的负担
IPV4 头部结构CPAL编程
IP选项部分数据域从Option开头即全为数据域内容,所以要注意偏移;
ethernetPacket msg;
byte time[18]={0x44,12,5,00,24,21,0,0,1,1,1,1,0x08,6,36,25,36,35};
byte streamid[6]={0x88,4,36,25,36,95};
byte eol[1]={0};
byte ip[10]={11,4,192,168,25,36,192,25,14,36};
msg.ipv4.Init();
msg.ipv4.optionTimeStamp.Init();
msg.ipv4.optionTimeStamp.SetData(0,time,12);
msg.ipv4.optionStreamID.Init();
msg.ipv4.optionStreamID.SetData(2,streamid,2);
msg.ipv4.optionSecurity.Init();
// msg.ipv4.optionStrictSourceRoute.Init();
// msg.ipv4.optionStrictSourceRoute.SetData(1,ip,10);
msg.ipv4.optionLooseSourceRoute.Init();
msg.ipv4.optionLooseSourceRoute.SetData(1,ip,10);
//msg.ipv4.optionRecordRoute.Init();
msg.ipv4.optionNOP.Init();
//msg.ipv4.optionEOL.SetData(0,eol,1);
msg.destination=ethGetMacAddressAsNumber("FF:FF:FF:FF:FF:FF");
msg.source=ethGetMacAddressAsNumber("01:05:00:00:00:36");
msg.SetSourceIPAddress(ip_Address(192.168.3.25));
msg.SetDestinationIPAddress(ip_Address(192.168.3.27));
//msg.icmpv4.Init();
//msg.icmpv4.SetData(0x00,time,10);
msg.icmpv4.parameterProblem.Init();
msg.icmpv4.parameterProblem.pointer=10;
msg.icmpv4.parameterProblem.SetData(4,time,20);
**选项默认没有添加到IPV4协议中,所以需要先初始化:
因为Option的数据域为全选项区域,在设置数据域的时候要加入offset
**
TCP相关知识点
TCP HEADER说解
TCP流量控制原理
TCP流量控制原理
TCP选项
选项最多为 40 字节;
选项总长度包括了种类和 len 个字节,种类主要来确定字节数 len;
(1)MSS,kind=2;只记录 TCP 数据的字节数,不包括头部;默认数值为 536 字节,典型值为 1460;
(2)允许选择确认,kind=4;只有 SYN (SYN + ACK)报文段才能包含;
(3)SACK,kind=5;任何报文段都可以包含,一个 SACK 块由一对 32 位序列号表示
(4)窗口缩放,kind=3;选项中使用一个 16 位数值的比例因子,表示将窗口字段值左移 0 ~ 14 位;只能出现在 SYN 报文段中,且通信双方都需要在 SYN 中包含该选项;
主动连接的一方发送了一个非 0 的比例因子但没有收到对方的窗口缩放选项,会将自己发送与接收的比例因子都设为 0;
根据接收缓存大小自动选取;
(5)时间戳(TSopt),kind=8;要求发送方在每个报文段中添加 2 个 4 字节的时间戳数值;
只能出现的握手过程的选项
- MSS 选项,握手时候就应该确立大小
- SACK 确认功能需握手时候确立
- 窗口缩放 需要在握手时候确认
发送方填写 TSval,接收方填写 TSecr;
**估算 TCP 连接的往返时间,设置重传超时**
这些时间戳也可作为 防回绕序列号(PAWS);提供了避免接收就报文段与判断报文正确性的
方法;
在高速网络中,32 位序列号很容易使用完然后又从 0 开始,假设前面第一个 32 位序列号范围内的某个报文段丢
失重传,但第二个 32 位序列号范围内的已经开始传输,接收方可能就无法区分接收到的报文段是属于重传的还
是第二个范围内的,此时通过发送时间戳可以进行区分,因此接收者可以将时间戳看作一个 32 位的扩展序列
号;
需要保证时间戳数值单调增长,并且每一个窗口的数据都至少增加 1;
16位校验和CheckSum计算原理
16位校验和计算
2.1 基本原理
IP/ICMP/IGMP/TCP/UDP等协议的校验和算法都是相同的,采用的都是将数据流视为16位整数流进行重复叠加计算。为了计算检验和,首先把检验和字段置为0。然后,对有效数据范围内中每个16位进行二进制反码求和,结果存在检验和字段中,如果数据长度为奇数则补一字节0。当收到数据后,同样对有效数据范围中每个16位数进行二进制反码的求和。由于接收方在计算过程中包含了发送方存在首部中的检验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全0或全1(具体看实现了,本质一样) 。如果结果不是全0或全1,那么表示数据错误。
unsigned short csum(unsigned char *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;//取反值
}
**TCP MSS与Ethernet MTU 定义 **
MTU(Maximum Transmission Unit,MTU)最大传输单元,是指网络能够传输的最大数据包长度,以字节为单位。MTU的大小决定了发送端一次能够发送报文的最大字节数。如果MTU超过了接收端所能够承受的最大值,或者是超过了发送路径上途经的某台设备所能够承受的最大值,就会造成报文分片甚至丢弃,加重网络传输的负担。如果太小,那实际传送的数据量就会过小,影响传输效率。
基于以太网帧一次最大传送的数据报文数据 即以太网负载大小 而非IP的负载
MTU默认最大字节为1500bytes=1518bytes-18bytes
TCP MSS?
TCP MSS(Maximum Segment Size)是指TCP协议所允许的从对方收到的最大报文长度,即TCP数据包每次能够传输的最大数据分段,只包含TCP Payload,不包含TCP Header和TCP Option。MSS是TCP用来限制application层最大的发送字节数。为了达到最佳的传输效能,TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往根据MTU值来计算(需要减去IP包头20字节和TCP包头20字节),所以通常MSS为1460=1500(MTU)- 20(IP Header) -20 (TCP Header)。
三次握手的过程
前提:A主动打开,B被动打开
-
在建立连接之前,B先创建TCB(传输控制块),准备接受客户进程的连接请求,处于LISTEN(监听)状态
-
A首先创建TCB,然后向B发出连接请求,SYN置1,同时选择初始序号seq=x,进入SYN-SEND(同步已发送)状态
-
B收到连接请求后向A发送确认,SYN置1,ACK置1,同时产生一个确认序号ack=x+1。同时随机选择初始序号seq=y,进入SYN-RCVD(同步收到)状态
-
A收到确认连接请求后,ACK置1,确认号ack=y+1,seq=x+1,进入到ESTABLISHED(已建立连接)状态。向B发出确认连接,最后B也进入到ESTABLISHED(已建立连接)状态。
简单来说,就是:
建立连接时,客户端发送SYN包(SYN=i)到服务器,并进入到SYN-SEND状态,等待服务器确认
服务器收到SYN包,必须确认客户的SYN(ack=i+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器进入SYN-RECV状态
客户端收到服务器的SYN+ACK包,向服务器发送确认报ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
在此穿插一个知识点就是SYN攻击,那么什么是SYN攻击?发生的条件是什么?怎么避免?
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。
SYN攻击就是 Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址 是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网 络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,
四次分手的过程
由于TCP**连接时是全双工的,因此每个方向都必须单独进行关闭。**这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的链接。收到一个FIN只是意味着这一方向上没有数据流动,既不会在收到数据,但是在这个TCP连接上仍然能够发送数据,知道这一方向也发送了FIN,首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
前提:A主动关闭,B被动关闭
有人可能会问,为什么连接的时候是三次握手,而断开连接的时候需要四次挥手?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再 发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
A发送一个FIN,用来关闭A到B的数据传送,A进入FIN_WAIT_1状态。
B收到FIN后,发送一个ACK给A,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),B进入CLOSE_WAIT状态。
B发送一个FIN,用来关闭B到A的数据传送,B进入LAST_ACK状态。
A收到FIN后,A进入TIME_WAIT状态,接着发送一个ACK给B,确认序号为收到序号+1,B进入CLOSED状态,完成四次挥手。
简单来说就是:
客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
A在进入到TIME-WAIT状态后,并不会马上释放TCP,必须经过时间等待计时器设置的时间2MSL(最长报文段寿命),A才进入到CLOSED状态。为什么?
为了保证A发送的最后一个ACK报文段能够到达B
防止“已失效的连接请求报文段”出现在本连接中
OK~是不是很难懂的感觉?那我们来说的“人性化点的”吧
握手时默认的SEQ是怎么获取
初始序列号
ISN 会随时间而改变,可被视为一个 32 位计数器,每 4 微妙加 1;
现代系统中对每一个连接设置随机的偏移量;
1.6 TCP状态
(1)TIME_WAIT,也称为 2MSL 等待状态
1.7 RST 报文段
(1)针对不存在端口的连接请求或端口处于 TIME_WAIT 状态时
(2)终止一条连接,如用户按下 crtl-c
(3)半开连接;服务器断电重启,客户端向其发送数据时,服务器回应 RST 报文段;
(4)时间等待错误;客户端在 TIME_WAIT 状态时,收到服务器之前发送的报文段,发送一个 ACK 报文段,然而服务器已经关闭,只能返回一个 RST 报文段,这会导致过早地从 TIME_WAIT 状态转移至 CLOSED 状态;
TCP超时与重传
基于时间
基于确定信息的构成
每个 TCP 连接的 RTT 均独立计算;
TCP流量控制原理
学术名词解释
MSL(Maximum Segment Lifetime)最大报文生存时间
每个TCP实现必须选择一个MSL。它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL时间。RFC 793指出MSL为2分钟,现实中常用30秒或1分钟。
2MSL
当TCP执行主动关闭,并发出最后一个ACK,该链接必须在TIME_WAIT状态下停留的时间为2MSL。这样可以(1)让TCP再次发送最后的ACK以防这个ACK丢失(被动关闭的一方超时并重发最后的FIN);保证TCP的可靠的全双工连接的终止。(2)允许老的重复分节在网络中消失。参考文章《unix网络编程》(3)TCP连接的建立和终止 在TIME_WAIT状态 时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置 SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。
TTL(time-to-live)生存时间字段
在IP首部中的8位字段。该字段不是存的具体时间,而是设置了数据报可以经过的最多路由器数。它制定了数据报的生存时间。TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1.当该字段值为0时,数据报就被丢弃,并发送ICMP报文通知源主机。
RTT(round-trip-time)往返时间
TCP超时与重传中最重要的部分就是对一个给定连接的往返时间RTT的测量。由于路由器和网络流量均会变化,因此这个时间可能经常会变化,TCP应该跟踪这些变化并相应地改变其超时时间。
MTU(Maximum Transfer Unit)最大传输单元
链路层的帧(frame)中的数据部分的最大字节数
以太网中的一般为1500字节
MSS(Maximum Segment Size) 最大报文段大小
TCP的报文段中的数据部分的最大字节数,MTU减去IPv4的Header和TCP的Header
IPv4的Header和TCP的Header一般都是20字节,则MSS=1500-20-20 = 1460字节
RTO(Retransmission Timeout) 超时重传时间
TCP中触发超时重传机制的时间,应略大于RTT
RFC2988中建议RTO = RTTS + 4 * RTTD
RTTD时RTT的偏差的加权平均值
对于i=1,RTTD[i] = 新RTT样本/2
对于i>1,RTTD[i] = (1 - b) * RTTD[i-1] + b * | 新RTT样本 - RTTD[i] |,建议b=1/4
————————————————
TCP半关闭
shutdown()接口实现单方向关闭,这样关闭Endpoint一侧将只能接收数据,不再向外发送数据!!!
TCP拥塞处理机制
一、摘要
在上一篇TCP 滑动窗口原理解析文章中,我们对 TCP 的滑动窗口原理进行一次总结,也提到了流量控制和拥塞控制。
本文我们重点来说说 TCP 的流量控制和拥塞控制的实现。
话不多说,直接上干货!
流量控制
在上篇文章中我们提到,TCP 通过接受方实际能接收的数据量来控制发送方的窗口大小,从而实现所谓的流量控制。
理想的情况下,假设不受外界影响,两台计算机在整个传输过程中,可以保持基本相同的窗口大小值。
而实际的情况,很难做到这一点,因为外部环境比较复杂,可能会出现一些意想不到的问题。
下面我们一起来看看有哪些因素可能会影响窗口大小值。
2.1、影响滑动窗口大小的因素介绍
在实际的数据传输过程中,发送方的窗口大小主要依赖于接受方的可用窗口大小来计算。
因此如果接受方的可用窗口发生变化,发送方的窗口大小也必然会发生变化。
比较常见能影响接受方的可用窗口发生变化的因素,有如下几个:
接受方的应用程序没办法及时读取数据,此时会影响滑动窗口大小值
接受方的系统资源非常紧张,操作系统可能直接减少可用窗口大小的缓存空间
我们先看看第一个案例!
图片
根据上图描述,大致的过程说明如下:
1.发送窗口和接收窗口初始大小为 360,客户端发送 140 字节数据后,可用窗口变为 220
2.服务端收到 140 字节数据后,可能因为某种阻塞,应用进程只读取了 40 个字节,还有 100 字节存在缓冲区,于是接收窗口收缩到了 260 (360 - 100),最后发送确认信息时,将窗口大小通过给客户端。
3.客户端收到确认和窗口通告报文后,发送窗口减少为 260
4.客户端再发送 180 字节数据,此时可用窗口减少到 80
5.服务端收到 180 字节数据后,可能又因为某种阻塞,应用程序没有读取任何数据,这 180 字节就直接留在了缓冲区,于是接收窗口收缩到了 80 (260 - 180),并再次发送确认信息时,通过窗口大小给客户端。
6.客户端收到确认和窗口通告报文后,发送窗口减少为 80
7.客户端发送 80 字节数据后,可用窗口变成 0
8.服务端收到 80 字节数据后,应用程序依然没有读取数据,这 80 字节留在了缓冲区,于是接收窗口收缩到了 0,并在发送确认信息时,通过窗口大小给客户端
9.最后发送方和接收方,可用窗口都变成 0
当可用窗口都收缩为 0,会发生了窗口关闭,这个对数据传输会造成非常严重的影响,具体等会在说。
我们继续看看第二个案例!
当服务端系统资源非常紧张的时候,操心系统可能会直接减少了接收方的缓冲区大小,此时应用程序又无法及时读取缓存数据,那么这时候就有严重的事情发生了,会出现数据包丢失的现象。
根据上图描述,大致的过程说明如下:
1.客户端发送 140 字节的数据,于是可用窗口减少到了 220
2.服务端收到 140 字节数据后,因为系统资源紧张,操作系统直接减少接收方的缓存空间,于是可用窗口大小收缩成 100 字节,此时又因为应用程序没有读取数据,收到的 140 字节一直留在了缓冲区中,最后发送确认信息时,通告窗口大小给对方。
3.可能客户端因为还没有收到服务端的通告窗口报文,不知道此时接收方的窗口收缩成了 100,客户端只会看自己的可用窗口还有 220,所以客户端就发送了 180 字节数据,于是可用窗口减少到 40。
4.服务端收到了 180 字节数据时,发现数据大小超过了接收窗口的大小,于是就把数据包丢弃掉。
5.客户端此时收到第 2 步服务端发送的确认报文和通告窗口报文,尝试减少发送窗口到 100,把窗口的右端向左收缩了 80,此时可用窗口的大小就会出现的负值。
因此,从上面的分析中可以发现,如果发生了先减少缓存,再收缩窗口,就会出现数据丢包的现象。
为了防止这种情况发生,TCP 规定是不允许先减少缓存又收缩窗口的,而是采用先收缩窗口,然后告知发送方,过段时间再减少缓存,这样就可以避免了丢包情况。
窗口关闭的问题
上文中我们提到当可用窗口都收缩为 0,会发生了窗口关闭,此时发送方会停止向接受方传递数据,直到接受方可用窗口变成非 0,再次向发送方通告可用窗口的大小,最后发送方再次重新发起数据传输。
如果这个接受方向发送方通告窗口的 ACK 报文在网络中丢失了,可能会造成死锁!
根据上图描述,大致的过程说明如下:
1.发送方向接受方发完 1001~2000 的数据,收到接受方的 ack 报文之后,可用窗口为 0
2.发送方不在向接受方传递数据,并且等待接受方的非 0 窗口同志
3.过了一段时间之后,接受方处理完数据,可用窗口增大,向发送方通告可用窗口的报文,很不幸,ack 报文丢失了
4.最后发送方和接受方,等在默默的等待对方的报文数据,造成了死锁的现象
因此,当发送方一直等待接收方的非 0 窗口通知,接收方也一直等待发送方的数据,如果不采取措施,这种相互等待的过程,会造成了死锁的现象。
为了解决这个问题,TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。
如果持续计时器超时,就会发送窗口探测 ( Window probe ) 报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。
根据上图描述,大致的过程说明如下:
1.如果接收窗口仍然为 0,那么收到这个报文的一方就会重新启动持续计时器
2.如果接收窗口不是 0,那么死锁的局面就可以被打破了
窗口探查探测的次数一般为 3 次,每次大约 30-60 秒(不同的操作系统实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。
糊涂窗口综合症
在上文中,我们提到可能因为接受方阻塞,来不及取走接收窗口里的数据,导致发送方的窗口越变越小。
到最后,可能接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。
就好像一个可以承载 50 人的大巴车,每次来了一两个人,就直接发车,这样玩下去,司机不迟早的破产。
要解决这个问题其实也不难,等乘客数量超过一半,也就是 25 个,就进行发车。
解决糊涂窗口综合症,主要从以下两个方向入手:
让接收方不通告小窗口值给发送方
让发送方避免发送小数据
接收方通常的解决策略如下:
当窗口大小小于 min( MSS,缓存空间/2 ) ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为 0,也就阻止了发送方再发数据过来。等到接收方处理了一些数据后,窗口大小 >= MSS,或者接收方缓存空间有一半可以使用,就可以把窗口打开让发送方发送数据过来。
发送方通常的解决策略如下:
使用 Nagle 算法来处理,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据:
要等到窗口大小 >= MSS 或是 数据大小 >= MSS
收到之前发送数据的 ack 回包
如果没满足上面条件中的一条,发送方就一直在囤积数据,直到满足上面的发送条件。
拥塞控制
在上文中我们也提到,面对复杂的网络环境,TCP 的流量控制能解决的问题比较有限,尤其是当网络出现拥堵的时候,这个时候 TCP 会采用拥塞控制来解决。
拥塞控制,其目的就是避免发送方的数据填满整个网络!
为了在发送方调节所要发送的数据量,我们需要定义了一个叫做拥塞窗口的概念,使用cwnd来表示。
在前面我们有提到过发送窗口swnd大小,取自于接收窗口rwnd的大小,两者基本上是约等于的关系,由于入了拥塞窗口的概念后,此时发送窗口的值是 swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值。
拥塞窗口cwnd值的变化情况,取自于网络环境
当网络出现拥堵,cwnd就会变小
当网络没有出现拥堵,cwnd就会变大
那 TCP 是如何知道当前网络是否出现拥堵呢?
一般来说,只要发送方没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。
当网络出现拥塞时,TCP 主要有以下四种主要的算法来控制发送量。
慢启动算法
拥塞避免算法
拥塞发生算法
快速恢复算法
下面我们依次来看看具体的实现逻辑。
重发类型与处理方式
超时重发
如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。
也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。
超时触发重传存在的问题是,超时周期可能相对较长。那是不是可以有更快的方式呢?
于是就可以用「快速重传」机制来解决超时重发的时间等待。
慢启动算法
TCP 在刚建立完连接后,首先是有个慢启动的过程,这个慢启动的意思就是一点一点的提高发送数据包的数量,防止一下子发送大量的数据,填充整个网络。
慢启动的算法,就一个规则:当发送方每收到一个 ACK,拥塞窗口cwnd的大小就会加 1。
整个慢启动的过程,可以用下图来描述。
-
其中cwnd=1表示可以传一个 MSS 大小的数据。
-
可以看出慢启动算法,发包的个数是成指数性的增长。
那是不是可以无限的增长呢?
答案肯定不是,慢启动有个门限ssthresh变量值。
当cwnd < ssthresh时,使用慢启动算法
当cwnd >= ssthresh时,就会使用拥塞避免算法
下面我们再来看看拥塞避免算法!
拥塞避免算法
当拥塞窗口cwnd超过慢启动门限ssthresh就会进入拥塞避免算法。
进入拥塞避免算法后,它的规则也比较简单:每当收到一个 ACK 时,cwnd增加1/cwnd。
假定ssthresh为 8,可以用下图来描述增长过程。
当 8 个 ACK 应答确认到来时,每个确认增加1/8,8 个 ACK 确认,cwnd一共增加 1,于是这一次能够发送 9 个 MSS 大小的数据,变成了线性增长。
所以,可以发现,拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶段,但是增长速度缓慢了一些。
就这么一直增长着,网络也可能会出现拥塞,一旦出现拥塞,就可能会出现丢包现象,这时就需要对丢失的数据包进行重传。
当触发了重传机制,也就进入了拥塞发生算法阶段。
拥塞发生算法
当网络出现拥塞,也就是会发生数据包重传,此时会使用拥塞发生算法,重传机制主要上文介绍的两种:
超时重传
快速重传
当发生超时重传时,sshresh 和 cwnd 的值会发生如下变化:
- ssthresh设为cwnd/2
- cwnd重置为1
整个过程可以用如下图来描述!
当进入超时重传的时候,基本上就重新进入了慢启动过程,慢启动的过程就是会突然减少数据流的,然后重新开始。
除此之外,还有另一种快速重传的机制,当接收方发现丢了一个中间包的时候,发送方收到 3 次重复的 ACK,会进入快速重传阶段,不必等待超时重传。
当发生超时重传时,sshresh 和 cwnd 的值会发生如下变化:
cwnd设为cwnd/2
ssthresh设置为cwnd
然后进入快速恢复算法阶段。
快速恢复算法
快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像超时重传那样重新开始。
进入快速恢复算法之后,主要的调整如下:
- cwnd设置为ssthresh + 3( 3 的意思是确认有 3 个数据包被收到了)
- 重传丢失的数据包
- 如果再收到重复的 ACK,那么cwnd增加 1
如果收到新数据的 ACK 后,设置cwnd为ssthresh,接着就进入了拥塞避免算法
整个过程可以用如下图来描述!
采用快速恢复算法,依然可以保持比较高的数据传输,不至于向超时重传那样,重新开始!
1.TCP 在滑动窗口的基础上提供了流量控制,避免客户端发送的数据超过服务端的接受能力,从而导致数据包丢失。
2.针对网络拥堵问题,TCP 提供了拥塞控制,避免发送的数据填满整个网络。
相关问题汇总(问答式)
SACK选项怎么解读(怎么表示接收数据漏洞信息)
上图所示:出现一条报文丢失:回复的ACK的ACKNUM 值就显示一直期望接收的分段起始值
同时在TCP的OPTION中添加入SACK信息:如果已经成功接收的数据报文为连续报文,可以记录有效报文的起始SEQ至最后一条报文的ACK_NUM值,如果在SACK有效长度范围内,出现多次丢失报文,可以通过多条SACK项值实现漏洞的记录。
为什么会发RST报文
在网络通信中,TCP(传输控制协议)连接的状态管理至关重要,以确保数据的可靠传输。TCP连接会经历多个状态,包括LISTEN(监听)、SYN-SENT(同步已发送)、SYN-RECEIVED(同步已接收)、ESTABLISHED(已建立)等。当你提到的场景中,如果连接处于非同步状态(如LISTEN、SYN-SENT、SYN-RECEIVED),并且发生了一些特定的情况,系统可能会发送一个RST(重置)包来终止该连接。
非同步状态及异常情况
非同步状态:
LISTEN:服务器等待进入连接的初始状态。
SYN-SENT:客户端发送SYN包后等待服务器响应SYN-ACK的状态。
SYN-RECEIVED:服务器接收到SYN包后发送SYN-ACK包,并等待客户端的ACK包。
异常情况:
-
不可接受的ACK:如果连接处于非同步状态,但收到的数据段(segment)中的ACK确认号(acknowledgment number)指向了一个尚未发送的数据,那么这个ACK是不可接受的。这可能是因为序列号(sequence number)或确认号(acknowledgment number)的混淆或错误。
-
安全级别或分区不匹配:在一些安全敏感的网络环境中,TCP连接可能要求特定的安全级别或分区(compartment)信息。如果收到的数据段的安全级别或分区信息与连接请求时指定的不匹配,这也可能触发RST包的发送。
- 针对SYN-SENT状态的测试
在你提到的“注意:此测试检查SYN-SENT状态”部分,测试的重点是检查当连接处于SYN-SENT状态时,系统如何响应上述异常情况。具体来说,如果客户端在发送SYN包后等待SYN-ACK时,收到了一个包含不可接受ACK的数据段,或者数据段的安全级别/分区与请求的不匹配,那么客户端应当发送一个RST包来终止这个连接。 -
为什么要发送RST包
RST(重置)包是一种TCP控制消息,用于立即终止一个TCP连接。在上述情况下,由于连接尚未达到ESTABLISHED状态,且出现了不可恢复的错误(如不可接受的ACK或安全/分区不匹配),继续尝试建立连接可能是徒劳的,甚至可能导致数据损坏或安全漏洞。因此,发送RST包是一种快速、有效的错误恢复机制。
如何通过SACK标明接收到重复的数据
接收到ACK报文的SACK的区间值小于ACK_NUM值的时候,即表示为数据重复DSACK声明
为关闭连接后要等待2MSL时间&怎么回避此等待时间
此时间内限制有哪些
此等待时间内
- 当前关闭的连接的源Endpoint&目标端的Endpoint对应IP与端口定义为不可重新使用
- 在2MSL期间,所有延迟到达的报文均会被抛弃
为了要等待2MSL时间
在TCP协议中,当连接处于TIME_WAIT状态时,该连接不能用于接收新的数据或建立新的连接。TIME_WAIT状态是TCP连接关闭过程中的一个阶段,用于确保在连接完全关闭之前,所有发送的数据包都已被对方正确接收并确认。这是为了防止由于网络中存在的延迟重复分组(delayed duplicate segments)导致的问题。
具体来说,TIME_WAIT状态的目的包括:
- 确保TCP报文段的最大生存时间(MSL,Maximum Segment Lifetime)已过,这样TCP报文段就不会在网络中滞留,导致新的连接接收到旧的报文段。
- 允许旧的连接重复的TCP报文段在网络中消逝,确保新的连接不会受到这些旧报文段的影响。
在TIME_WAIT状态下,尽管该端口的连接不能被复用,但是服务器上的其他端口或相同端口上的其他连接(如果有的话)仍然可以正常工作,接收和发送数据。TIME_WAIT状态是针对特定的连接(由四元组<源IP地址,源端口,目的IP地址,目的端口>唯一标识)而言的。
如果客户端或服务器希望尽快重用处于TIME_WAIT状态的端口,可以通过
- 调整TCP的TIME_WAIT时长(通常是2MSL,即两倍的报文段最大生存时间,通常为60秒)
- 通过配置SO_REUSEADDR套接字选项(在绑定端口之前设置)来允许重用本地地址和端口但请注意,SO_REUSEADDR选项的使用场景有限,并不能完全替代TIME_WAIT状态的功能,且其行为可能依赖于具体的操作系统实现。
总之,当TCP连接处于TIME_WAIT状态时,该连接不能用于接收新的数据或建立新的连接。
在TIME_WAIT状态下收到数据报文处理方式
- 直接丢弃:
在TIME_WAIT状态下,连接已经被视为“半关闭”或“完全关闭”,因此,理论上不应该再收到任何数据报文。
如果在这个阶段收到了数据报文,由于TCP连接已经不再处于活跃状态,因此这些数据报文通常会被直接丢弃。 - 发送RST重置报文(在某些实现中):
某些TCP/IP协议栈的实现可能会在TIME_WAIT状态下收到非预期的数据报文时,发送一个RST(Reset)重置报文给对方,以告知对方该连接已经不再有效。
RST报文的作用是强制关闭一个连接,告诉对方这个连接上有错误发生,必须立即释放连接。 - 不会进行任何接收操作:
在TIME_WAIT状态下,TCP连接的接收缓冲区已经被清空或不再使用,因此即使收到了数据报文,也不会进行任何接收操作。 - 能够响应接收数据,数据将会丢弃不做任何执行与上传
TIME_WAIT时候,相应的端口还是理解为连接状态,能够响应该端口接收到的任何数据报文段,并做出正确的ACK响应,数据将直接丢弃,不向上传递
零窗口探测报文如何识别
具体的代码如下,总的来说这段代码的作用是检测零窗口探测包,并对其做出适当的标记,以便 Wireshark 进行后续的分析和显示。主要检测以下三个条件,如果都满足,则认为是一个零窗口探测数据包。
TCP Keepalive报文的格式
TCP Keepalive Probe报文:
**TCP保活探测报文是将之前TCP报文的序列号减1,**并设置1个字节,内容为“00”的应用层数据。这样做的目的是触发对端发送ACK响应,从而确认连接是否存活。
**TCP Keepalive ACK报文:**因为SEQ不对,对端会回复正确的ACK挑战报文
TCP保活探测确认报文是对保活探测报文的确认。当对端收到Probe报文后,如果连接存活,会回复ACK报文。
零窗口控制报文ACK响应报文结构&处理机制
检测接收窗口状态:
当TCP连接的接收方缓存区满时,会向发送方发送一个窗口大小为0的ACK报文,告知发送方暂停发送数据。然而,如果接收方在窗口重新打开并发送了非零窗口大小的ACK报文后(可接收时候主动发一条ACK),该ACK报文丢失,发送方将无法得知接收窗口已经重新打开,从而陷入等待状态。TCP零窗口探测机制就是为了解决这一问题而设计的。
防止死循环:
如果没有零窗口探测机制,发送方可能会因为等待一个永远不会到来的ACK而陷入死循环,导致连接无法继续传输数据。通过发送探测报文,发送方可以检测接收方的窗口是否重新打开,从而避免这种情况的发生。
TCP零窗口探测的实现方式
发送探测报文:
当TCP连接的接收方窗口大小为0时,发送方会启动一个定时器(通常称为零窗口探测定时器),每隔一段时间发送一个探测报文。这个探测报文通常是一个携带了序列号但数据长度为0的TCP报文段,其目的是迫使接收方发送一个ACK响应。
接收方响应:
接收方在收到探测报文后,会回复一个ACK报文。如果此时接收方的窗口已经重新打开,那么ACK报文中将包含一个非零的窗口大小。发送方在收到这个ACK后,就可以继续发送数据了。
调整探测间隔:
如果发送方在发送了多个探测报文后仍未收到接收方的非零窗口ACK响应,它会根据一定的算法(如指数退避算法)逐渐增加探测报文的发送间隔。这样做可以减少网络拥塞并避免对接收方造成不必要的压力。
零窗口探测报文格式
这个探测报文通常是一个携带了序列号但数据长度为0的TCP报文段,其目的是迫使接收方发送一个ACK响应。
- TCP 段大小为 0
- 接收窗口大小为 为实际可用窗口大小值
- Seq Num 等于 Next Seq Num
- Ack Num 等于上一个数据包的 Ack Num(即为zeroWindow报文的值)
当处于CLOSED状态时候对请求的处理方式
- 如果请不带ACK&RST,此将直接回复RST报文,且SEQ=0 ACK=0
- 如果请求带ACK,此时将回复SEQ=收到的ACK值,ACK=0,回复RST报文
TCP 状态机各种状态如何识别
-
如果确定syn_rcvd状态
当从LISTEN或是SYN_SENT状态转syn_rcvd状态后,此时如果再收到synSegment,将回复最后一次syn+ack;相应的SEQ与ACK并不会有变化
-
LISTEN状态
每次发送SYN,如响应ACK将使用新的ACK值进行回复; -
SYN_SENT状态
-
连接创建
如何检测TCP连接进入CLOSED状态
- 向DUT发送除带RST外报文帧,含其他标志的报文或无FLAGS,此时如果处于CLOSED将回复RST
如果发送的消息报文不带ACK标识
此时回复的RST重置消息报文的SEQ=0
如果发送的消息报文带ACK标识
此时回复RST重置消息报文的SEQ等于收到数据的ACK值,因为此对方期望回复的SEQ是ACK指定的
在TCP(传输控制协议)通信中,Stream of full-sized segments指的是一系列满大小的数据段流。这些满大小的数据段通常指的是达到TCP协议所允许的最大字节大小的数据包。TCP协议通过面向连接、端到端和可靠的数据包发送来确保数据传输的可靠性。
关于Stream of full-sized segments 满大小数据段的ACK响应机制
**数据段大小:**满大小的数据段允许包含TCP协议所规定的最大字节数。这个大小取决于多种因素,包括网络配置、操作系统和应用程序的设置等。
流量控制:
TCP使用滑动窗口机制来实现对发送方的流量控制。发送方可以在不等待每个数据段确认的情况下连续发送多个满大小的数据段。然而,发送窗口的大小会受到接收方给出的窗口值的限制,以确保接收方能够及时处理接收到的数据。
确认机制:
在TCP连接中,发送方发送数据段后,需要接收方的ACK(确认)来确认数据已经成功接收。对于满大小的数据段流,接收方可能会采用延迟ACK的策略,即不是对每个数据段都立即发送ACK,而是在收到一定数量的数据段或经过一段时间后发送ACK,以提高网络效率。
数据传输效率:
通过连续发送满大小的数据段,TCP可以提高数据传输的效率。然而,在网络拥塞或延迟较大的情况下,过多的数据段可能会导致接收方处理不过来,从而影响数据传输的可靠性。
为了验证DUT(被测试设备)在接收到一系列满大小的数据段时是否能够按照预期发送ACK,可以进行专门的测试用例,如TCP_OUT_OF_ORDER_05。在这个测试用例中,测试者会发送一些满尺寸段以填满DUT的接收窗口缓冲区,并验证DUT是否能为所有数据段发送ACK,并且对于每个偶数个数据段发送,接收到的ACK数量至少是该数的一半。
总的来说,Stream of full-sized segments是TCP通信中重要的组成部分,它对于提高数据传输效率和确保数据传输的可靠性具有重要意义。
关于全尽寸的数据流的确认机制:每第二个流需要确认
在TCP(传输控制协议)中,当传输一个由满大小段(full-sized segments)组成的流时,确认机制(ACK)起着至关重要的作用。以下是对“在满大小段的数据流中,至少应该对每个第二个段发送一个ACK”这一说法的详细解释:
TCP的确认机制:
TCP使用确认(ACK)机制来确保数据的可靠传输。发送方发送数据段后,需要接收方的ACK来确认数据已经成功接收。
ACK包含确认号,指示接收方期望接收的下一个字节的序列号,从而告诉发送方哪些数据已经被成功接收。
满大小段的数据流:
在高效的数据传输中,特别是在接收窗口完全打开的情况下,发送方可能会连续发送多个满大小的数据段。
满大小段指的是数据段的大小接近或等于TCP连接的最大段大小(MSS)。
为什么至少对每个第二个段发送ACK:
根据TCP协议的行为,接收方应该至少对每个第二个数据段发送一个ACK。这是为了确保发送方能够及时了解数据传输的状态,并在必要时进行重传。
这种确认策略有助于提高数据传输的效率和可靠性,因为它允许发送方在继续发送更多数据之前,确认先前发送的数据已被成功接收。
优化与延迟ACK:
尽管TCP协议建议至少对每个第二个段发送ACK,但在实际应用中,为了优化性能,接收方可能会采用延迟ACK的策略。
延迟ACK意味着接收方在接收到数据段后不会立即发送ACK,而是会等待一段时间(通常是200毫秒),以便将ACK与需要沿该方向发送的数据一起发送,或者等待接收更多的数据段后再发送一个累积的ACK。
然而,即使采用延迟ACK策略,接收方仍然需要确保及时发送足够的ACK,以满足至少对每个第二个段进行确认的要求。
综上所述,TCP协议中建议至少对每个第二个满大小段发送一个ACK,以确保数据传输的可靠性和效率。这种确认策略是TCP协议中重要的一部分,有助于维护数据传输的稳定性和性能。
如何确认当前状态为【TIME_WAIT】
TCP连接关闭过程:
当TCP连接中的一方(通常是客户端)准备结束连接时,它会发送一个FIN(结束)包给另一方(通常是服务器)。
服务器接收到FIN包后,会发送一个ACK包进行确认,并进入CLOSE_WAIT状态。
随后,当服务器也准备好关闭连接时,它会发送一个FIN包给客户端。
客户端接收到服务器的FIN包后,会发送一个ACK包进行确认,并进入TIME_WAIT状态。
TIME_WAIT状态的特点:
TIME_WAIT状态是TCP连接关闭过程中的一个中间状态,仅出现在主动关闭连接的一方(通常是客户端)。
在TIME_WAIT状态下,客户端会等待一段时间(通常是两个最大报文段生存时间,即2MSL),以确保服务器收到的FIN包被正确确认,并且防止旧的连接数据包干扰新的连接。
TIME_WAIT状态的重要性:
TIME_WAIT状态的存在是为了确保TCP连接的可靠关闭,防止旧的连接数据包干扰新的连接。
如果没有TIME_WAIT状态,可能会出现数据包的混乱和错误的连接建立,导致网络通信的不可靠性。
总结来说,TCP确认当前状态为TIME_WAIT的过程涉及TCP连接的关闭过程、TIME_WAIT状态的特点以及使用网络诊断工具或查看操作系统网络状态信息来确认状态。TIME_WAIT状态的存在对于确保TCP连接的可靠关闭至关重要。
该状态操作表现
当TCP连接处于TIME_WAIT状态时,尝试重新开启该端口进行新的TCP连接可能会遇到以下结果:
连接失败:
如果操作系统遵循标准的TCP行为,并且端口仍然处于TIME_WAIT状态,那么在该端口上尝试建立新的TCP连接将会失败。因为TCP协议规定,一个端口不能被同时用于多个连接,特别是当旧连接还在TIME_WAIT状态时。
等待时间:
TIME_WAIT状态会持续一段时间,通常是两个最大报文段生存时间(2MSL)。MSL的具体值可能因操作系统和配置而异,但在RFC 1122中建议的MSL值是2分钟。这意味着在TIME_WAIT状态期间,你将无法在该端口上建立新的TCP连接。
系统资源占用:
处于TIME_WAIT状态的连接会占用系统资源,包括内存和端口号。如果大量的连接长时间处于TIME_WAIT状态,可能会导致系统资源耗尽,影响新连接的建立。
解决方法:
**设置SO_REUSEADDR选项:**在某些操作系统(如Linux)中,可以通过设置socket的SO_REUSEADDR选项来允许在TIME_WAIT状态下的端口被重新使用。然而,这并不意味着旧的TIME_WAIT连接会被立即终止或删除,但它允许在同一端口上建立新的连接。
**调整TIME_WAIT超时时间:**虽然不推荐这样做,但可以通过修改系统配置来调整TIME_WAIT的超时时间。然而,这可能会增加数据包混淆和连接错误的风险。
使用不同的端口:如果可能的话,可以使用不同的端口来避免TIME_WAIT状态的问题。
总结:
当TCP连接处于TIME_WAIT状态时,尝试重新开启该端口进行新的TCP连接通常会导致连接失败。你需要等待TIME_WAIT状态结束,或者使用其他方法(如设置SO_REUSEADDR选项或使用不同的端口)来避免这个问题。同时,过多的TIME_WAIT连接可能会占用系统资源,因此需要注意管理和优化。
针对已经建立连接,重复发起连接请求情况
当TCP已经建立连接后,如果再次尝试建立相同的连接(即使用相同的源IP、目标IP、源端口和目标端口),服务端会根据接收到的SYN报文中的源端口号来进行处理。以下是两种可能的情况及其处理方式:
SYN报文中的源端口号与历史连接不同:
- 服务端会认为这是新的连接请求,并启动三次握手过程来建立新的连接。
- 如果旧连接(即之前已经建立的连接)中服务端有数据要发送给客户端,但由于客户端的连接已经关闭(或处于不同的状态),客户端的内核会回复RST报文给服务端,服务端收到后会释放旧连接。
- 如果服务端在一段时间内没有发送数据给客户端,并且超过了TCP保活机制的检测周期,服务端也会因为探测不到客户端的存活而释放旧连接。
SYN报文中的源端口号与历史连接相同: - 服务端会识别到这是针对已建立连接的重复SYN报文(尽管SYN报文的序列号可能是随机的)。
- 服务端会回复一个携带了正确序列号和确认号的ACK报文,这个ACK报文被称为Challenge ACK。
- 客户端在接收到Challenge ACK后,会注意到序列号与自己期望的不一致,于是会回复RST报文给服务端。
- 服务端收到RST报文后,会释放原有的连接。
RST重置报文段的SEQ如何设置
- 如果在非CLOSED状态下,且主动发送RST,此时SEQ应该是当前待发送的序号值
- 如果收到发送数据报文段,且当前在非CLOSED状态,且收到报文段有ACK标志时候,此时RST中SEQ=接收到数据的ACK值
- 如果在CLOSED状态的时候,如果收到报文没有ACK,RST重置报文段的SEQ=0 如果收到的报文带ACK,此时RST的SEQ=ACK数值
TIME_WAIT状态特点与识别
此状态时相应的端口连接还是维持,但只能接收数据,但是该接收的数据内容并不会上传给应用层,只是对接收到数据消息段做出相应的回应,比如
- 收到FIN回ACK
- 如果收到SYN将回复RST
维活报文格式&应用
KeepAlive与keepAliveAck报文的格式:
- 报文为ACK报文即ACK置位
- KeepAlive的序列号=收到最大的ACK值-1,同时ACK值=最后一次发送的ACK包的ACK值
- payload可以为空也可以为一个字节值
- KeepAliveAck 返回的依然ACK报文;同时ACK值+1;
回退一字节,用于维活探测
零窗口声明&零窗口通报
TCP 窗口更新声明
当窗口大小符合接收数据要求的时候,将主动发送窗口更新声明报文:
此报文为ACK结构报文,且内容与最后一次ACK内容一致,仅是WIN值为当前可用值
因为此为标准ACK报文,可带SACK选项内容;下图为SACK的使用示例
TCP状态机各状态如果识别与确认
指令方式识别
netstat命令是一个在Unix和类Unix系统(包括Linux)中用于显示网络连接、路由表、接口统计等信息的命令行工具。以下是netstat命令的详细使用说明:
一、命令格式
bash
netstat [options]
二、常用选项
-a 或 --all
显示所有活动的网络连接和监听的端口。
-n 或 --numeric
以数字形式显示地址和端口号,不进行DNS解析。
-t 或 --tcp
仅显示TCP连接。
-u 或 --udp
仅显示UDP连接。
-l 或 --listening
仅显示处于监听状态的套接字。
-p 或 --program
显示与每个套接字关联的进程名和PID。
-r 或 --route
显示路由表信息。
-s 或 --statistics
显示每个协议的统计信息。
-e 或 --extend
显示扩展信息,如用户ID、组ID等。
-c 或 --continuous
每隔一段时间连续显示网络连接状态。
何时以何种格式发送RST重置报文段
针对不存在端口的连接请求即CLOSED状态
当一个连接请求(SYN报文段)到达本地,但是并没有相关进程在目的端口进行侦听时,TCP会发送一个RST报文段来中断这个连接请求。
在这种情况下,RST报文段的序列号字段通常被设置为0,因为到达的SYN报文段并没有打开ACK位字段。
RST报文段的ACK号字段大小等于接收到的初始序列号加上该报文段中数据的字节数(尽管SYN报文段并不包含数据,但SYN位在逻辑上仍会占用一个字节的序列号空间)。因此,ACK号等于初始序列号加上数据长度0,再加上SYN位的1字节。
终止一条连接:
虽然终止一条连接的正常方法是由通信一方发送一个FIN报文段(有序释放),但在任何时刻,我们都可以通过发送一个RST报文段替代FIN来终止一个连接(终止释放)。
在这种情况下,RST报文段的序列号(SEQ)和确认号(ACK)的设置会根据具体的TCP实现和连接状态有所不同。但一般来说,序列号会设置为当前连接的某个有效值,而确认号会设置为期望接收的下一个字节的序列号。
TCP接收到一个根本不存在的连接上的分节:
如果TCP接收到一个与其当前不存在或已关闭的连接相关的数据分节,它可能会发送一个RST报文段来通知对方连接已经不存在或已关闭。
在这种情况下,RST报文段的序列号(SEQ)和确认号(ACK)的设置同样会根据具体的TCP实现和连接状态有所不同。
关于SEQ与ACK的设置:
序列号(SEQ):在RST报文段中,序列号字段通常用于标识TCP连接中的特定位置。在针对不存在端口的连接请求的情况下,序列号通常被设置为0。但在其他情况下,序列号可能会根据TCP实现和连接状态而有所不同。
确认号(ACK):在RST报文段中,确认号字段用于确认已经成功接收到的最后一个字节的序列号。在针对不存在端口的连接请求的情况下,ACK号等于接收到的初始序列号加上数据长度(即使数据长度为0)再加上SYN位的1字节。但在其他情况下,确认号会根据具体的TCP实现和连接状态而有所不同。
在建议连接前的状态收到ACK值不可接受,或是SEQ值超窗口
- LISTEN状态:因为没有外发ISN值,如果收到ACK消息报文或是带ACK消息报文,发送相应的RST,且SEQ=收到的ACK报文的ACK值
- SYN_SENT状态:因为已经外发了ISN,如果ACK值为不可接受值,将发送RST,且SEQ=收到的ACK报文的ACK值
- SYN_RECV状态:因为已经交互了ISN,如果收到ACK值不可接受,或是SEQ超出窗口限制,均会发送RST,并SEQ=收到的ACK报文的ACK值
哪些阶段应用层的读取调用可以返回数据至应用层
- 在FINWAIT_1 时候,通知对方我无数据需要发送了,但是可以接收数据,并上传应用层
- FINWAIT_1时候收到ACK,确认表示对端已经知道你关闭了,此时进入FINWAIT_2状态,此时接收端口依然有效,可以接收数据,并上传应用层
- CLOSE_WAIT层可以接收并上支应用层
ACK挑战报文段格式与发送时机
ACK挑战报文:用于在收到错误的SEQ或是ACK时候,告知对方正确的SEQ与ACK值的报文段
发送时机
- 在已经建立连接状态后,收到所有错误的SEQ或是ACK时候均会以ACK挑战或是纠正报文回应,告知对方发送错了即在CLOSED状态前所有状态
- 但是在建立连接前,即握手过程中的状态【LISTEN】,【SYN_RECV】,【SYN_SENT】收到错误的SEQ或是无效的ACK时候均会发送RST终止当前连接操作
- 【CLOSED】不管收到正确的带是错误的SEQ&ACK 均回复RST,并根据是否带ACK决定RST的SEQ段的数据值,如果收到报文段无ACK标识,SEQ=0,如果有ACK标识,则SEQ=收到报文段中的ACK数据值
如何判断总线出现拥塞
在TCP中丢包是用于判断拥塞发生与否的指标,并决定是否实施相应的响应措施!
ARP基本应用场景
ARP相关定义与结构
前面 14 个字节构成标准以太网的首部,前两个字段 DST 和 SRC 分别表示 以太网的目的地址 和 以太网的源地址,以太网的目的地址如果是 ff:ff:ff:ff:ff:ff 全部为 1 表示广播地址,在同一广播域中的所有以太网接口可以接收这些帧。后面紧跟着的是 ARP 请求的长度/类型,ARP 请求 和 ARP 应答这个值为 0x0806。
硬件类型字段:指明了发送方想知道的硬件地址的类型,以太网的值为1;
协议类型字段:表示要映射的协议地址类型,IP为0X0800;
硬件地址长度和协议地址长度:指明了硬件地址和高层协议地址的长度,这样ARP帧就可以在任意硬件和任意协议的网络中使用。对于以太网上IP地址的ARP请求或应答来说,它们的值分别为6和4;
操作字段:用来表示这个报文的类型,ARP请求为1,ARP响应为2,RARP请求为3,RARP响应为4;
发送端的以太网地址:源主机硬件地址,6个字节;
发送端IP地址:发送端的协议地址(IP地址),4个字节;
目的以太网地址:目的端硬件地址,6个字节;
目的IP地址:目的端的协议地址(IP地址),4个字节。
ARP相关知识点记录
二层广播arp请求
https://blog.csdn.net/wj31932/article/details/132326263
单播arp请求消息
Ip冲突探查arp请求
arp宣告使用此ip地址
协议字段填充
ARP攻击类型与方式
ARP 是一种非常不安全的协议,目前已经有很多涉及 ARP 的攻击,最主要的就是使用代理 ARP 功能假扮主机,对 ARP 请求作出应答,通过伪造 ARP 数据包来窃取合法用户的通信数据,造成影响网络传输速率和盗取用户隐私信息等严重危害。
ARP 主要攻击方式分为下面这几种
-ARP 泛洪攻击:通过向网关发送大量 ARP 报文,导致网关无法正常响应。首先发送大量的 ARP 请求报文,然后又发送大量虚假的 ARP 响应报文,从而造成网关部分的 CPU 利用率上升难以响应正常服务请求,而且网关还会被错误的 ARP 缓存表充满导致无法更新维护正常 ARP 缓存表,消耗网络带宽资源。
-ARP 欺骗主机攻击:ARP 欺骗主机的攻击也是 ARP 众多攻击类型中很常见的一种。攻击者通过 ARP 欺骗使得局域网内被攻击主机发送给网关的流量信息实际上都发送给攻击者。主机刷新自己的 ARP 使得在自己的ARP 缓存表中对应的 MAC 为攻击者的 MAC,这样一来其他用户要通过网关发送出去的数据流就会发往主机这里,这样就会造成用户的数据外泄。
-
欺骗网关的攻击: 欺骗网关就是把别的主机发送给网关的数据通过欺骗网关的形式使得这些数据通过网关发送给攻击者。这种攻击目标选择的不是个人主机而是局域网的网关,这样就会攻击者源源不断的获取局域网内其他用户韵数据.造成数据的泄露,同时用户电脑中病毒的概率也会提升。
中间人攻击: 中间人攻击是同时欺骗局域网内的主机和网关,局域网中用户的数据和网关的数据会发给同一个攻击者,这样,用户与网关的数据就会泄露。 -
IP地址冲突攻击: 通过对局域网中的物理主机进行扫描,扫描出局域网中的物理主机的 MAC 地址,然后根据物理主机的 MAC 进行攻击,导致局域网内的主机产生 IP 地址冲突,影响用户的网络正常使用。
- ARP欺骗
ARP欺骗是指通过一定的手段使自己拥有其它的身份,从而达到欺骗的目的。ARP协议的工作原理决定ARP欺骗只会存在于局域网内。
5.1. 对路由器ARP表的欺骗
原理是截获网关数据。它通知路由器一系列错误的内网MAC地址,并按照一定的频率不断通知路由器,使真实的地址信息无法保存在路由器中,结果路由器的所有数据只能发送给错误的MAC地址,造成正常主机无法收到信息。
5.2. 对内网主机的网关欺骗
原理是冒充网关。它的原理是冒充网关,不停的向网络中发送构造好的广播ARP帧,让其它主机的ARP高速缓存中保存的网关的IP地址对应的MAC地址是本机的MAC地址,让被欺骗的主机向本机发数据,本机就可以截获这些数据,如果本机向外转发这些数据,那些被欺骗的主机感觉一切正常,它们感觉不到数据已经被截获了;本机如果不转发这些数据,那些被欺骗的主机就无法对外进行通信了。
当然,还有其它欺骗方式:如欺骗某一台主机、用ARP进行泛洪攻击等。
- ARP欺骗攻击的防范
建立MAC数据库,把局域网内所有网卡的MAC和对应的IP地址记录下来,以便及时查询备案。
用监控软件可以监控是否受到ARP攻击。例如网关监听:网关上面使用监控程序截取每个ARP帧,用分析软件分析这些ARP帧。ARP欺骗攻击的帧一般有以下两个特点,满足之一可视为攻击帧:(1)以太网数据包头的源地址、目标地址和ARP数据帧的协议地址不匹配;(2)ARP数据包的发送和目标地址不在自己网络网卡MAC数据库内,或者与自己网络MAC数据库 MAC->IP 不匹配。查看这些数据包(以太网数据包)的源地址(也有可能伪造),就大致知道哪台机器在发起攻击了。
ARP请求操作类型
二层广播ARP请求
应用场景:访问同网段ip,arp缓存里没有对应表项,就会发出二层广播arp消息,如
特点:arp请求消息体里,目的mac地址为空,全00,待目的设备填入自身值。即使此目标MAC值全为FF也不影响,正常的响应,基本可视为全0与全FF的广播地址是同样的效果
有对应的响应消息。响应消息为单播模式,源MAC填写为自身的MAC值,并在负载中将自身的IP与MAC值写入的发送端的MAC与IP地址区域。特点是广播请求,单播响应
应答消息为单播,源ip和源mac为请求的目的设备。
单播arp请求消息(节点在线检测)
在arp缓存已有的对应表项,为检测对方是否在线,发出的单播arp探查消息
目的:
Unicast Poll – Actively poll the remote host by
periodically sending a point-to-point ARP Request o it, and delete the entry if no ARP Reply is received from N successive polls. Again, the timeout should be on the order of a minute, and typically N is 2。
当arp广播请求过程完成(其实就是主机收到了设备的ARP应答),双方都知道对方的IP–MAC映射,也会在自己的ARP表中生成这个映射;由于ARP老化机制第二种–单播轮询,主机会定期向设备发送点到点的单播ARP请求报文,用来确认对方是否存在,确认这条ARP缓存是该更新(主要是更新老化定时器)还是删除,同时,使用单播还可以减少网络中的ARP报文数量。
1. 如果发送单播ARP无响应,如何处理?
【自述未求证】如果无响应,则表明相应的节点可能不存在,或是相应的IP与MAC的绑定关系已经更新,此时应该删除此ARP记录,重新进行ARP请求进行更新
2. 如果有响应但是ARP回复的IP与MAC绑定关系与ARP表不一致如何处理?
因为ARP是链路层协议,所以无需IP与TCP/UDP进行数据的处理,此时因为MAC值是正确的,只是相应的IP值有变换,才能确保网络中有节点响应,但是因为此时IP已经更新,所以回复的时候将使用最新的IP与MAC绑定关系进行回复,主机接收到回复后,应该确认收到的信息是否与记录一致,如果不一致即要更新当前ARP表
如下图:
Arp的缓存表现如下:
下图arp单播请求,隔一段时间发出,在广播消息后,不间断发出。
应答消息为单播消息
————————————————
Ip冲突探查arp请求[^1]
应用场景,插拔网线,网卡激活或者dhcp获取ip后发出,用于探查广播域里是否有ip冲突的现象。一般发出三次(没冲突的情况下)。三次都没有响应,就进入下一个arp宣告,宣告正式使用这个ip地址。两者都是在没有请求的情况下发送的,因此它们是免费的。但从技术上讲,它们与免费ARP并不完全相同。
特征:二层广播消息,arp消息体里,源ip和目的mac为空,全0。间隔1秒发三次。因为是探测相关的IP存在与否,不应该更新IP与MAC的绑定关系,所以源IP与目标MAC都是设置为0,0表示为无效值
注意,包中没有提供完整的映射。**发送方IP被设置为全零,这意味着它不能映射到发送方MAC地址。目标器的MAC地址为全零,即不能映射到目标器的IP地址。这两者都是不确定广播域里是否存在,所以先为00。**这是有意这样做的,因为发送ARP探测的原因是为了防止IP冲突。如果目标IP地址已经在使用中,那么网络上的其他主机会根据ARP探测的内容无意中更新它们的ARP缓存,这是非常不可取的。
修改ip为dhcp自动获取,发现获取地址后,有arp探查消息发出,获取地址为192.168.209.139
发出三次arp探查消息。
Ip冲突时,arp探查发出一次,有响应,就不用此地址,静态的话,会提示ip冲突,地址变成169.254.xx.xx。
如图:已知环境里存在ip为192.168.209.141,就把pc 的ip修改为209.141,看看抓包结果
流程:修改ip后,发出arp探查,第一次就有响应,然后报ip冲突,使用本地链路地址169.254.240.20,同样三次探查消息发出,并用此ip请求网关mac地址,网关不处理此类地址的请求,所以不停发出arp消息。
因为无法获得网关mac地址,所以无法上网。
arp宣告使用此ip地址
应用场景:在插拔网线或者dhcp获取地址后,arp探查没有ip冲突,宣告
CAPL网络脚本设计
组播程序设计
发送端要使用IpSetMulticastInterface(Socket,ifindex)将指定的SOCKET关链到指定的Adapter上才能完成正常的收发操作相关操作一旦完成,即发送时候将使用对应的Adapter的MAC与VLAN配置信息,如果不进行SetMultiInterface操作,无法实现组播报文的发送操作
配置
接收端需要使用IpJoinMulticastGroup 将相应的SOCKET加入指定的组播IP信息,添加到组播组内,配置需要注意的几点:
1.UdpOpen(0/IpGetAddressAsNumber(“192.168.23.4”)/, 30602)打开UDP端口操作
1.1 打开的IP地址应该配置为特定的IP地址的时候,将无法接收组播报文,所以如果需要接收组播报文,需将IP设置为0
1.2 作为接收端时候,需指定监测的端口,不能使用0,但是作为发送端可以不指定端口,自动分配端口
因为IP只用于路由报文,PORT才是决定由哪个应用接口进行处理:所以IP=0表示所有IP接口报文只要其PORT为指定的PORT都由当前程序处理;;;PORT=0表示由系统分配,并非全部PORT都引用当前程序
on start
{
Dword port = 12345;
long result; // function result
// calculate the numeric multicast address.
ipv4MulticastAddr = IpGetAddressAsNumber( ipv4MulticastAddrStr );
udpMulticastSocket = UdpOpen(0, 5566); // open an UDP socket...
if (udpMulticastSocket != INVALID_SOCKET)
{
result = IpJoinMulticastGroup( udpMulticastSocket, 2, ipv4MulticastAddr );
result = IpSetMulticastInterface(udpMulticastSocket,2);
if (result == 0)
{
// successfully joined.
udpSendTo(udpMulticastSocket,ipGetAddressAsNumber("224.123.111.222"),30602,"Hello",6);
// result = ipLeaveMulticastGroup(udpMulticastSocket,2,ipGetAddressAsNumber("224.123.111.222"));
udpSendTo(udpMulticastSocket,ipGetAddressAsNumber("192.168.23.4"),30602,"Hello",6);
udpSendTo(udpMulticastSocket,ipGetAddressAsNumber("192.168.23.14"),30602,"Hello",6);
udpSendTo(udpMulticastSocket,ipGetAddressAsNumber("192.168.23.34"),30602,"Hello",6);
udpReceiveFrom(udpMulticastSocket,buf,200);
}
else
{
writeLineEx(1, 3, "IpJoinMulticastGroup: Error %d", result);
}
}
else
{
writeLineEx( 1, 3, "UdpOpen: Failed to open socket.");
}
}
OnUdpReceiveFrom(dword socket, long result, dword address, dword port, char buffer[], dword size)
{
if(result==0x00)
{
writeEx(-3,1,"%s",buffer);
udpReceiveFrom(socket,buf,200);
// IpLeaveMulticastGroup( udpMulticastSocket, ifIdx, ipv4MulticastAddr );
}
else
{
writeEx(-3,1,"Result=%d",result);
}
}
on preStop
{
// leave multicast group.
IpLeaveMulticastGroup( udpMulticastSocket, ifIdx, ipv4MulticastAddr );
// close the socket
UdpClose(udpMulticastSocket);
}
ARP相关问题合集
ARP响应目标地址不为本身IP时候不进行学习与处理
ARP响应的过程
**ARP请求:**主机A会发送一个ARP请求广播报文,这个报文中包含了主机A的IP地址和MAC地址,以及它想要查询的主机B的IP地址。因为此时主机A不知道主机B的MAC地址,所以在ARP请求报文中的目的MAC地址字段会使用广播地址(如FF-FF-FF-FF-FF-FF)。
**ARP响应:当网络中的其他设备(包括主机B和其他主机或网络设备)收到这个ARP请求报文时,它们会检查报文中的目标IP地址是否与自己相匹配。如果匹配(如主机B发现目标IP地址是自己的),则它会将自己的MAC地址封装在ARP响应报文中,并发送一个单播报文给主机A。这个单播报文的目的MAC地址是主机A的MAC地址,而源MAC地址是主机B的MAC地址。
ARP缓存:当主机A收到主机B的ARP响应报文后,它会将主机B的IP地址和MAC地址的映射关系保存在自己的ARP缓存表中,以便后续通信时直接使用,而无需再次发送ARP请求。
响应目标地址不是本身地址的情况
如果ARP响应的目标地址不是本身地址(即不是接收ARP响应报文的设备的IP地址),那么通常情况下,这个设备不会对这个ARP响应报文进行特别的处理或学习。因为ARP响应报文是单播的,其目的MAC地址已经明确指向了某个特定的设备(在这个例子中是主机A),所以如果目标地址不是该设备的IP地址,那么该设备就不会认为这个ARP响应是给自己的,因此也不会去更新自己的ARP缓存表。
然而,有一种特殊情况需要注意,那就是网络中的其他设备(如路由器或交换机)可能会根据ARP报文的内容来更新自己的内部表项(如MAC地址表或ARP表),但这与ARP响应报文的目标地址是否为本身地址无直接关系,而是与这些设备的具体功能和配置有关。
综上所述,ARP响应目标地址不是本身地址时,接收该报文的设备通常不会进行学习或更新自己的ARP缓存表
ARP表项的老化与更新
ARP表项更新
ARP表项的更新通常发生在以下几种情况:
ARP请求与响应:
当一个设备需要与另一个设备通信,但不知道其MAC地址时,会发送一个ARP请求广播到网络上的所有设备。
如果某个设备的IP地址与ARP请求中的目标IP地址匹配,该设备会回复一个ARP响应,包含自己的MAC地址。
请求设备收到ARP响应后,会将目标设备的IP地址和MAC地址添加到自己的ARP表中,以便后续通信。
ARP报文的接收:
如果收到的ARP报文满足特定条件(如源IP地址与入接口IP地址在同一网段,且不是广播地址,目的IP地址是本接口IP地址或VRRP虚拟IP地址),系统也会更新ARP表项。
此外,如果ARP报文的源IP地址在入接口的ARP表中已经存在对应表项,也会对ARP表项进行更新。
免费ARP:
免费ARP是一个特殊类型的ARP请求,其目的IP地址是本机IP地址。发送免费ARP可以用于判断局域网内是否有重复IP地址的主机,或在更新MAC地址(如换网卡)后更新其他主机的ARP缓存表项。
ARP老化处理
ARP老化处理是指ARP缓存表中的条目在一定时间内没有被使用而被删除的过程。其主要目的是保持ARP缓存表的准确性和时效性,减少不必要的网络负担和内存消耗。
生存时间(TTL):
每个ARP缓存条目都有一个生存时间(TTL),即条目的存活时间。在Linux系统中,这个生存时间一般默认为20分钟左右(但具体值可能因系统配置而异)。
老化机制:
Linux内核会定期检查ARP缓存表中的条目,并删除那些生存时间已到的过时条目。
如果在生存时间内继续与该IP地址通信,那么该条目的生存时间会被重置,以保持其有效性。
配置调整:
在某些情况下,可以根据网络环境和需求调整ARP老化参数,如老化超时时间和老化探测次数等。
合理的调整可以提高网络可靠性,但过小的老化时间会增加系统资源消耗,而过大的老化时间则可能导致ARP缓存表项无法及时刷新。
总结
ARP表项的更新和老化处理是网络通信中不可或缺的机制。通过ARP请求与响应、ARP报文的接收以及免费ARP等方式,可以确保ARP表的准确性和完整性。同时,通过ARP老化处理机制,可以定期清理过时或无效的ARP缓存条目,保持ARP缓存表的时效性和高效性。这些机制共同作用,提高了网络通信的效率和安全性。
VLAN TC2测试相关内容与知识点
VLAN技术本是二层技术,用来隔绝广播域,限制广播帧对于局域网带宽的影响。因为VLAN在二层,理论上VLAN不可以设置IP,不同VLAN之间不能直接通信,将某些端口加入到VLAN中,那么这些端口所连接的主机也就不能和其他VLAN中的主机进行通信。要想不同VLAN的主机能够通信,则必须借助路由器来进行路由转发。
switch的look up table原理解析
交换机的基本原理是实现两层交换数据的转发 。交换机工作于OSI参考模型的第二层,即数据链路层。交换机内部的CPU会在每个端口成功连接时,通过将MAC地址和端口对应,生成一张LUT(look up table)表。在今后的通讯中,发往该MAC地址的数据包将仅送往其对应的端口,而不是所有的端口。
MAC地址学习
交换机拥有一条很高带宽的背部总线和内部交换矩阵。交换机的所有的端口都挂接在这条背部总线上,控制电路收到数据包以后,处理端口会查找内存中的地址对照表以确定目的MAC(网卡的硬件地址)的NIC(网卡)挂接在哪个端口上,通过内部交换矩阵迅速将数据包传送到目的端口,目的MAC若不存在,广播到所有的端口,接收端口回应后交换机会“学习”新的MAC地址,并把它添加入内部MAC地址表中。这就为MAC地址的学习过程。
端口的地址学习:即需要从此端口转发出去的报文,将会与相应的MAC与端口进行绑定存入ARL表中
MAC地址老化算法
轮询方式老化
由于LUT表的资源是有限的。对于交换机使用过程中,MAC地址的数量不能一直的添加。在LUT表中除去交换过程中废弃的MAC地址,就叫做mac地址的老化。在交换机的工作过程中,将表中的MAC地址都存在一个循环链表中。在数据交换过程中轮询链表,对于轮询到的MAC地址counter不变。对于没有轮询到的mac地址counter减1,当counter为0时。从列表中删除MAC地址。
计时方式老化
老化时间(Aging time )默认为300秒。从一个地址记录加入地址表以后开始计时,如果在老化时间内各端口未收到源地址为该MAC地址的帧,那么,这些地址将从动态转发地址表(由源MAC地址、目的MAC地址和它们相对应的交换机的端口号)中被删除。静态MAC地址表不受地址老化时间影响
交换机转发方式
交换机收到数据帧后,会有三种处理方法:直通转发、碎片隔离和存储转发。
以太网数据帧类型
交换机优点
直接转发
直通转发是交换机只读取数据帧的前 14 个字节就进行转发。由于读取的数据量固定,发送方和接收方的速度需要一致,导致无法桥接不同速率的以太网。另外,只读取前 14 个字节,会跳过了 FCS 域,因此无法检测并丢弃 CRC 校验错误的数据帧。
碎片隔离
碎片隔离是读取数据帧的前 64 个字节就进行转发,可以防止转发小于 64 字节的残帧。但是如果出现 CRC 错误,还是会转发数据帧。也无法桥接不同速率的以太网。
存储转发
存在转发会读取数据帧全部内容再进行转发。这样就可以识别残帧和 CRC 校验错误帧,并将它们丢弃。交换机还能对数据帧进行缓存,因此可以桥接不同速率的以太网。
交换机的处理能力指标
交换机的处理能力也叫做背板容量或交换机容量。容量单位是 bit/s(比特每秒),值越大,说明交换机在单位时间内传输的数据越多。
当交换机的所有端口的总带宽小于交换机的容量时,交换结构为非阻塞,即带宽充裕,没有等待处理的情况。反之,当所有端口总带宽超过交换机的容量时,叫做交换机结构过载。
交换机是千兆端口时,处理能力达到端口数 × 2 × 1Gbit/s 的数值,就是非阻塞。其中 × 2 表示上行和下行都是 1Gbit/s 的全双工通信。假如交换机有 24 个端口,背板容量到达 24 × 2 × 1G = 48Gbit/s ,就是非阻塞。这是从背板容量考量
交换机功能
交换机的完整功能说明,可以查看官网的产品文档,里面进行了详细的描述。
MAC 地址数
MAC 地址数是指一台交换机最大可以学习到的 MAC 地址表数量。
生成树功能
为了避免二层环路,我们使用生成树协议( STP ),让交换机知道对方的存在,具体做法是在交换机之间交换 BPDU 数据帧。详情可看《图解 STP 》和《图解 RSTP 和 MSTP 》。
链路聚合
链路聚合是将交换机的多条线路汇聚成一条逻辑线路在网络中使用。有多个称呼:端口聚合、链路捆绑、绑定等。
如果不使用链路聚合功能,直接将交换机的多个物理端口连接起来,可能会导致网络环路。如果使用生成树协议,又会避开某些链路,导致只有一条物理链路可用。如果使用链路聚合,把几条物理链路聚合成一条逻辑链路,即使某一条物理链路断开,由于逻辑线路还有其它物理链路在维持,因此通信也不会中断,到达线路冗余的效果。
VLAN
将广播域分割成一个个逻辑网段的功能叫做 VLAN 。
VLAN的报文格式
VLAN Tag包含TPID(Tag Protocol Identifier,标签协议标识符)和TCI(Tag Control Information,数据帧控制信息)两个部分,如下所示:
各参数解释如下:
TPID:表示数据帧类型,0x8100 表示 IEEE 802.1Q 帧(C-VLAN),0x88A8表示S-VLAN;
PCP:Priority Code Point(3 bits),表示数据帧优先级,数值越大,优先级越高;
DEI:Drop eligible indicator(1 bit),丢弃资格标识符,表示 MAC 地址封装是否符合规范格式;
CFI:Canonical Format Indicator(1 bit),标准格式标识符;
VID:VLAN identifier(12 bits),表示帧所属的VLAN。取值范围: 0~4095。
**交换机转发队列的级别通常涉及多个层次和配置选项,以确保不同优先级和类型的流量在网络中得到适当的处理。以下是根据参考文章整理的交换机转发队列级别的相关信息:
交换机转发报文等级与队列管理
队列数量与索引:
交换机上每个出接口通常有多个队列,用于缓存和转发报文。例如,一些交换机上每个出接口可能有8个队列,队列索引从0到7。
队列类型:
EF(加速转发)队列:这是一种高优先级的队列,用于满足低时延业务需求。EF队列中的报文在调度时会优先得到处理,以确保其获得低时延。当接口发生拥塞时,EF队列的报文会优先发送,但为了避免低优先级队列得不到调度,EF队列会以设置的带宽限速。
AF(确保转发)队列:满足需要带宽保证的关键数据业务。每个AF队列分别对应一类报文,用户可以设定每类报文占用的带宽。
BE(尽力而为)队列:通常用于低优先级或默认业务。在资源有限的情况下,BE队列的报文可能会被延迟或丢弃。
队列调度算法:
优先队列PQ(Priority Queuing)调度:严格按照队列优先级的高低顺序进行调度。只有高优先级队列中的报文全部调度完毕后,低优先级队列才有调度机会。
加权轮询调度WRR(Weight Round Robin):在队列之间进行轮流调度,根据每个队列的权重来调度各队列中的报文流。这种调度方式可以确保所有队列中的报文都能得到服务,但权重较大的队列会得到更多的服务机会。
队列配置与优先级映射:
交换机通常支持将不同的流量分类映射到不同的队列中。这可以通过设置802.1p优先级、DSCP值或其他流量标记来实现。
配置时,可以创建不同的DiffServ域,将802.1p优先级映射为PHB(每跳行为)行为,并为报文着色。然后,在交换机入接口上绑定这些DiffServ域。
队列的拥塞管理:
当网络发生拥塞时,交换机使用队列技术来管理流量。不同的拥塞管理技术可以根据各自的调度算法,实现对队列流量按照优先级发送。
队列调度策略可以根据业务需求进行配置,以确保关键业务得到足够的带宽和低时延,而低优先级业务在带宽不足时可以得到适当的处理。
综上所述,交换机转发队列的级别涉及多个方面,包括队列数量、类型、调度算法、配置与优先级映射以及拥塞管理等。通过合理配置这些参数,可以确保网络中的流量得到高效、公平和有序的处理。**
交换机地址学习理论与实践
交换机地址学习主要涉及到交换机如何学习并维护一个MAC地址表,以便能够高效地进行数据转发。以下是交换机地址学习的几个关键点:
地址学习过程:
当交换机从某个接口收到一个数据帧时,它会检查该数据帧的源MAC地址。
如果这个源MAC地址已经存在于交换机的MAC地址表中,交换机会更新该记录的时间戳,以表示该设备仍然活跃。
如果源MAC地址不存在于MAC地址表中,交换机会将该MAC地址与接收到该数据帧的端口关联,并将其添加到MAC地址表中。
MAC地址表的作用:
- MAC地址表是交换机用于记录MAC地址和端口映射关系的表
- 当交换机需要转发一个数据帧时,它会根据数据帧的目的MAC地址在MAC地址表中查找对应的出接口。
- 如果找到匹配的MAC地址,交换机会将数据帧从对应的出接口转发出去。
地址学习的方式:
- 动态学习:交换机通过接收数据帧并检查其源MAC地址来学习MAC地址。
- 静态配置:管理员可以手动在交换机上配置静态的MAC地址和端口映射关系。
MAC地址表的管理:
- MAC地址表项有老化时间,如果某个MAC地址在一段时间内没有被使用,其对应的表项会被从MAC地址表中删除,以释放资源。
- 交换机通常支持查看MAC地址表的命令,如华为交换机上的display mac-address命令。
VLAN与MAC地址学习:
- 当交换机端口绑定VLAN时,交换机在MAC地址表中记录的MAC地址会关联到相应的VLAN。
这使得交换机能够在转发数据时区分不同VLAN的数据,从而实现VLAN之间的隔离。
其他考虑因素:
- 交换机还需要防止网络中出现环路现象,通过STP(生成树协议)等机制构建无环路的网络拓扑结构。
- 交换机的工作过程还包括数据包的接收、转发、防止环路以及MAC地址表的维护等多个方面。
交换机ARL配置表格式与内容
交换机地址表,通常也被称为MAC地址表或CAM(Content-Addressable Memory)表,其格式和内容通常包括以下几个关键要素:
目的MAC地址:
这是MAC地址表中最主要的条目,表示了交换机想要转发数据包的目标设备的MAC地址。
MAC地址是一个48位的标识符,由6个字节(12个十六进制字符)组成。例如:00-0A-95-9D-68-16。
设备所属的VLAN:
VLAN(Virtual Local Area Network,虚拟局域网)是用于在交换机上创建逻辑隔离的广播域的技术。
MAC地址表项会记录该MAC地址所属的VLAN编号,以便交换机能够正确地将数据包转发到相应的VLAN。
出接口:
出接口表示交换机将从哪个物理或逻辑端口(如GE0/0/1、TenGigabitEthernet 1/0/1等)转发数据包。
这个信息告诉交换机数据包应该被发送到哪里。
MAC表项类型:
MAC表项类型表示该MAC地址表项是如何生成的,包括静态、动态、安全、Sticky等。
这些类型描述了MAC地址的来源和特性,例如是否可以被老化(即随时间删除)、是否由用户手动配置等。
老化时间:
- 老化时间是指动态MAC地址表项在交换机中保持活跃的最长时间。
- 如果在这段时间内没有再次从该MAC地址接收到数据包,该表项将被自动删除,以释放资源。
- 老化时间的设置有助于交换机应对设备移动或离开网络的情况。
其他信息(视交换机型号和功能而定):
某些交换机可能还包括其他信息,如MAC地址的学习时间戳、MAC地址的优先级、与MAC地址关联的安全设置等。
归纳起来,交换机地址表的基本格式可以表示为:
目的MAC地址:00-0A-95-9D-68-16
VLAN:10
出接口:GE0/0/2
MAC表项类型:dynamic
老化时间:300秒(或5分钟)
802.1P优先级策略
802.1p优先级是一种流量优先级控制标准,它工作在媒体访问控制(MAC)子层,使得二层交换机能够提供流量优先级和动态组播过滤服务。以下是关于802.1p优先级的详细解释:
定义与位置:
802.1p优先级定义在二层802.1Q标签头中的TCI字段中,和VLAN ID一起使用。具体来说,它位于TCI字段的高位起16-18bit字段,长度为3bit。
取值范围:
802.1p优先级的取值范围是0-7,其中0代表最低优先级,7代表最高优先级。
优先级分类与应用:
**最高优先级(7):**通常应用于关键性网络流量,如路由选择信息协议(RIP)和开放最短路径优先(OSPF)协议的路由表更新。
**优先级6和5:**主要用于延迟敏感的应用程序,如交互式视频和语音。
**优先级4到1:**主要用于受控负载的应用程序,如流式多媒体和关键性业务流量。
**优先级0:**是默认值,在没有设置其他优先级值的情况下自动启用。
配置与实现:
在交换机上,管理员可以根据需要配置802.1p优先级,将不同的流量分类映射到不同的优先级队列中。这可以通过设置802.1p优先级、DSCP值或其他流量标记来实现。
配置时,可以创建不同的DiffServ域,将802.1p优先级映射为PHB(每跳行为)行为,并为报文着色。然后,在交换机入接口上绑定这些DiffServ域。
作用与意义:
802.1p优先级的主要作用是为不同的网络流量提供不同的处理优先级,以确保关键业务得到足够的带宽和低时延,而低优先级业务在带宽不足时可以得到适当的处理。
通过合理配置802.1p优先级,管理员可以优化网络性能,提高网络资源的利用率,并满足各种业务的需求。
为什么要划分VLAN
减少广播风暴
VLAN最大的好处是可以隔离冲突域和广播域,试想,如果一个局域网内有上百台主机,如果一旦产生广播风暴,那么,这个网络就会被彻底的瘫痪。
可以通过vlan还划分广播与,这样使得广播被限制在每一个vlan里面,而不会跨VLAN传播。
不同vlan之间的成员在没有三层路由的前提下是不能互访的,这也是一种安全的考虑。
网络管理方便
另外一个好处就是管理灵活,当一个用户需要切换到另外一个网络时,只需要更改交换机的vlan划分即可,而不用换端口和连线。
VLAN的益处
限制广播域:广播域被限制在一个VLAN内,节省了带宽,提高了网络处理能力。
增强局域网的安全性:不同VLAN内的报文在传输时是相互隔离的,即一个VLAN内的用户不能和其它VLAN内的用户直接通信。
提高了网络的健壮性:故障被限制在一个VLAN内,本VLAN内的故障不会影响其他VLAN的正常工作。
灵活构建虚拟工作组:用VLAN可以划分不同的用户到不同的工作组,同一工作组的用户也不必局限于某一固定的物理范围,网络构建和维护更方便灵活。
端口镜像
将某个端口接收和发送的数据帧复制到镜像端口的功能叫做端口镜像,被复制的源端口叫做监控端口。
为了分析网络故障或检测网络中的流量,交换机会将收到的数据帧复制一份并转发到网络分析设备或流量监控设备中。
交换机每秒传送报文量计算
要计算以太网100M(兆位/秒)每秒能传输多少报文,我们首先需要明确几个关键参数:
**以太网帧的大小:**以太网帧的大小是可变的,但有一个最小和最大限制。最小帧大小(不包括前导码和帧开始定界符)通常是64字节,而最大帧大小(标准以太网)是1518字节(包括14字节的以太网头部和4字节的FCS/CRC)。但在实际中,由于MTU(最大传输单元)的限制,常见的最大帧大小是1500字节(不包括以太网头部和FCS/CRC)。
带宽:100M(兆位/秒)或100 Mbps(兆比特每秒)。注意,这里的单位是“位”而不是“字节”。1字节 = 8位。
效率:实际的网络传输可能由于各种原因(如帧间隔、错误重传等)而不是100%的效率。但在这里,为了简化计算,我们假设效率为100%。
基于上述参数,我们可以计算每秒能传输的最大和最小报文数:
最小报文数:假设每个报文都是最小帧大小(64字节),则每秒能传输的报文数为:
每秒报文数(最小)=
64 字节×8 位/字节
100 Mbps
512 位/报文
100×10
6
位/秒
≈1,953,125 报文/秒
最大报文数:假设每个报文都是最大帧大小(1500字节),则每秒能传输的报文数为:
每秒报文数(最大)=
1500 字节×8 位/字节
100 Mbps
12000 位/报文
100×10
6
位/秒
≈8333 报文/秒
注意:这些计算是基于理论值和假设的,实际网络中的性能可能会受到多种因素的影响。
QoS 优先级队列
QoS 是 Quality of Service 的缩写,也叫做服务质量。当数据通过网络设备时,根据通信种类控制通信优先级和带宽的功能。通常是将声音、视频等数据定义为高优先级,高优先数据优先处理,保障这类数据的稳定和低延迟。
除了交换机在二层进行的 QoS 控制外,还有路由器和三层交换机的三层( IP )的 QoS 控制,以及 TCP 进行的四层的 QoS 控制。
IEEE 802.1p 标准完成了对二层的 QoS 优先级控制的标准化工作。通过 3bit 长度的优先级控制信息,定义了从 0 到 7 的 8 个优先级,即 CoS 值(服务等级值),交换机会优先转发值大的数据帧。
MAC 地址过滤
为了网络安全,只让指定的设备接入网络。二层交换机提供了以数据帧的头部信息进行过滤的功能。具体过程是,先设置一个过滤条件,比如目的 MAC 地址、源 MAC 地址等,满足条件的数据帧通过,阻断不满足条件的数据帧。
考虑到伪造 MAC 地址的情况发生,还可以跟 802.1X 一起使用。三层交换机或路由器可以根据 IP 头部信息完成 IP 通信过滤的功能。
基于端口的认证
在交换机中,只有通过认证的客户端才能使用有线端口。这个功能由 IEEE 802.1X 完成标准化,对接入 LAN 的客户端进行认证的机制。
当 PC 连接交换机时,认证过程启动。根据发送方的 MAC 地址信息进行客户端识别,通过用户名、口令或证书等认证信息进行用户认证。对于没有认证的客户端发来的数据帧,交换机只接收包含认证信息的数据帧,其余的全部丢弃。对于认证失败的客户端发来的数据帧,交换机就直接丢弃不会进行转发。
要使用基于端口的认证功能,客户端的电脑和交换机都要支持 802.1X 认证功能,缺一不可。
802.1X 认证中使用 PPP 的扩展协议 EAP ,通过 EAPOL 协议封装 EAP 认证消息,然后在 LAN 中进行传输。认证结束之前,客户端电脑只能进行 EAPOL 通信。
网络管理
远程管理、监控和配置网络设备可以使用 SNMP 协议。SNMP 协议可以对整个网络结构内的交换机和其它网络设备进行集中统一的管理。
被 SNMP 管理的网络设备叫做 Agent ,管理网络的设备叫做 Manager 。
交换机组成
交换机的基本架构是由 RJ-45 接口、PHY 、MAC 等模块的 NIC 和管理由 NIC 收发帧缓存、转发表的软件组成,通过查看转发表信息,在 NIC 之间进行数据帧交互。
二层机交换机的ARL表每个项也是有老化时间的!两种方式实现老化处理
1.每次扫描ARL表时候,未扫描到的项计数器counter减1,减到0时丢弃
2.每个表项的计时器到0的时候,老化结束,丢弃
ICMP相关知识点
ICMP 的全称是 Internet Control Message Protocol(互联网控制协议),它是一种互联网套件,它用于IP 协议中发送控制消息。也就是说,ICMP 是依靠 IP 协议来完成信息发送的,它是 IP 的主要部分,但是从体系结构上来讲,它位于 IP 之上,因为 ICMP 报文是承载在 IP 分组中的,就和 TCP 与 UDP 报文段作为 IP 有效载荷被承载那样。这也就是说,当主机收到一个指明上层协议为 ICMP 的 IP 数据报时,它会分解出该数据报的内容给 ICMP,就像分解数据报的内容给 TCP 和 UDP 一样。
ICMP 协议和 TCP、UDP 等协议不同,它不用于传输数据,只是用来发送消息。由于 IP 协议现在有两类版本:IPv4 和 IPv6 ,所以 ICMP 也有两个版本:ICMPv4 和 ICMPv6。
ICMP报文分类:差错控制报文&查询报文
ICMP(Internet Control Message Protocol,互联网控制消息协议)报文主要用于在IP网络中传输控制和错误信息。ICMP报文根据其功能和用途可以分为两大类:差错报告报文和查询报文。
差错报告报文
差错报告报文用于报告IP数据报在传输过程中遇到的问题,并通知发送方进行相应的处理。这类报文主要包括以下几种:
终点不可达(Destination Unreachable)
类型值:3
代码标号:0-15,表示引发终点不可达错误类型的具体错误原因有16种可能。例如,网络不可达(代码0)、主机不可达(代码1)、协议不可达(代码2)、端口不可达(代码3)等。
当路由器或主机无法将IP数据报发送到指定目的地时,会丢弃该数据报,并向源主机发送终点不可达报文。
源点抑制(Source Quench)
类型值:4
代码标号:0
当网络拥塞时,路由器会向源主机发送源点抑制报文,告知源主机应该降低发送数据包的速率,以缓解网络拥塞。
时间超时(Time Exceeded)
类型值:11
代码标号:0或1,其中0表示TTL(Time-To-Live)超时,1表示分片重组超时。
当路由器接收到的数据报的TTL字段值为0时,或目的主机在规定时间内没有收到所有的数据分片时,会丢弃数据报并向源主机发送时间超时报文。
参数问题(Parameter Problem)
类型值:12
代码标号:0或1,其中0表示数据报文的首部字段值被修改,1表示该数据报文在网络中传输要求加上可选字段但实际上没有加上。
当路由器或目的主机发现IP数据报的首部字段值有问题时,会丢弃数据报并向源主机发送参数问题报文。
改变路由(Redirect)
类型值:5
代码标号:0、1、2、3,分别代表不同的路由改变情况。
当路由器发现存在更优的路由路径时,会向源主机发送改变路由报文,告知源主机使用更优的路由路径。
查询报文
查询报文主要用于网络故障诊断和网络信息探测。这类报文主要包括以下几种:
回送请求(Echo Request)和回送应答(Echo Reply)
类型值:8(请求)、0(应答)
代码标号:0
回送请求和回送应答报文是ICMP中最常用的报文类型之一,它们通过发送和接收特定的ICMP报文来检测目的节点是否可达。这也是ping命令实现的基础。
时间戳请求(Timestamp Request)和时间戳应答(Timestamp Reply)
类型值:13(请求)、14(应答)
代码标号:0
时间戳请求和应答报文用于测量数据报文在两个主机之间往返所需的时间,提供了一种基本的时钟同步机制。
地址掩码请求(Address Mask Request)和地址掩码应答(Address Mask Reply)
类型值:17(请求)、18(应答)
代码标号:0
地址掩码请求和应答报文用于请求和获取子网掩码信息,但在现代网络中,这一功能通常被DHCP等协议所取代。
路由器询问(Router Solicitation)和路由器通告(Router Advertisement)
类型值:10(询问)、9(通告)
代码标号:0
路由器询问和通告报文主要用于无盘工作站等无法保存网关信息的设备,通过发送路由器询问报文来询问网关信息,并接收路由器通告报文以获取网关信息。
总结来说,ICMP报文通过差错报告报文和查询报文两大类,为IP网络提供了重要的控制和错误信息传输机制,有助于网络的故障诊断和信息探测。
ICMP协议
协议报文结构与说明
- ICMP经常被认为是IP的附属协议。它传递差错报文以及其他需要注意的信息。ICMP报文通常被IP层或者更高层协议(TCP/UDP)使用。一些ICMP报文把差错报文返回给用户进程
- ICMP报文是在IP数据吧内部被传输的。ICMP本身是网络层协议。但是,它的报文不是如设想的那样直接传送给数据链路层,实际上,ICMP报文首先封装成IP数据报,然后再传送给下一层
- 在IP数据报中的协议字段值是1就表示其IP数据是ICMP报文
完整的ICMP报文类型如下:
差错报告报文:ICMP总是把差错报文报告给原始的数据源
类型3:终点不可达
类型4:源点抑制
类型11:超时
类型12:参数问题
类型5:改变路由(路由重定向)
查询报文
类型8或0:回送请求或回答
类型13或14:时间戳请求或回答
类型17或18:地址码请求或回答
类型10或9:路由器查询通告
ICMP 的主要功能
对于 ICMP 的功能,主要分为两个:查询与网络诊断
ICMP 的第一个功能是确认 IP 包是否能够成功到达目标地址,当两个设备进行互联时,其中一个设备发送给另一个设备的 IP 包如果没有到达,就会生成 ICMP 数据包发送给设备共享。
ICMP 的第二个功能是进行网络诊断,经常使用 ICMP 数据包的两个终端程序是 ping 和 traceroute,traceroute 程序用于显示两台互联网设备之间可能的路径并测量数据包在 IP 网络上的时延。ping 程序是 traceroute 的简化版本,我们经常使用 ping 命令来测试两台设备之间网络是否正常,ping 还可以显示两台设备之间的延迟情况,并准确报告数据包到达目的地并返回后所花费的时间。
上表显示的 ICMP 通知类型主要分为两类:有关 IP 数据报传递的 ICMP 报文,这类报文也叫做差错报文(error message),以及有关信息采集和配置的 ICMP 报文,这类报文也被称为查询报文、信息类报文。
信息类报文包括回送请求和回送应答(类型 8 和 类型 0 ),路由器公告和路由器请求(类型 9 和 类型10 )。最常见的差错报文类型包括目标不可达(类型 3 )、重定向(类型 5)、超时(类型 11)。
ICMP 目标不可达(类型 3)
我们知道,路由器无法将 IP 数据报发送给目标地址时,会给发送端主机返回一个目标不可达(Destination Unreachable Message) 的 ICMP 消息,并且会在消息中显示不可达的具体原因。
ICMP 重定向消息(类型 5)
如果路由器发现发送端主机使用了次优的路径发送数据,那么它会返回一个 ICMP 重定向(ICMP Redirect Message) 的消息给这个主机。这个 ICMP 重定向消息包含了最合适的路由信息和源数据。这种情况会发生在路由器持有更好的路由信息的情况下。路由器会通过这样的 ICMP 消息给发送端主机一个更合适的发送路由。
主机 Host 的 IP 地址为 10.0.0.100。主机的路由表中有一个默认路由条目,指向路由器 G1 的 IP 地址 10.0.0.1 作为默认网关。路由器 G1 在将数据包转发到目的网络 X 时,会使用路由器 G2 的 IP 地址 10.0.0.2 作为下一跳。
当主机向目的网络 X 发送数据包时,会发生以下情况:
IP 地址为 10.0.0.1 的网关 G1 在其所连接的网络上接收来自 10.0.0.100 的数据包。
网关 G1 检查其路由表,并在通往数据包目的网络 X 的路由中获取下一个网关 G2 的 IP 地址 10.0.0.2。
如果 G2 和 IP 数据包的源地址标识的主机位于同一网络中(也就是 Host 主机),那么 G1 会向主机发送 ICMP 重定向消息。ICMP 重定向消息建议主机直接将发送到网络 X 的数据包发送至 G2,因为 Host - G2 这是通往目的地的较短路径。
网关 G1 将原始数据包转发到其目的地。
当然,根据主机的配置,Host 主机也可以选择忽略 G1 给它发送的 ICMP 重定向消息。但是,这样就享受不到 ICMP 重定向带来的两大好处,即
优化数据在网络中的转发路径;流量更快到达目的地
降低网络资源利用率,例如带宽和路由器 CPU 负载
如果 Host 主机采用了 ICMP 提供的重定向路径的话,那么 Host 就会直接把数据包发送至网络 X,如下图所示
在主机为 G2 作为下一跳的网络 X 创建路由缓存条目后,这些优势在网络中可见:
交换机和路由器 G1 之间链路的带宽利用率在两个方向上都会降低。
由于从主机到网络 X 的流量不再流经此节点,因此路由器 G1 的 CPU 使用率降低。
主机和网络 X 之间的端到端网络延迟得到改善。
ICMP 重定向示例如下:
ICMP端口不可达(Kind=3 Code=3)
一般与UDP共同使用,如果一个UDP数据被目标机接收到,IP层往上送的时候,UDP检测发现无相应的接口对应的服务程序来处理这组数据,此时就会生成一个端口不可达错误消息报文。
ICMP 超时消息(类型 11)
在 IP 数据包中有一个叫做 TTL(Time To Live, 生存周期) ,它的值在每经过路由器一跳之后都会减 1,IP 数据包减为 0 时会被丢弃。此时,IP 路由器会发送一个 ICMP 超时消息(ICMP TIme Exceeded Message, 错误号 0)发送给主机,通知该包已经被丢弃。
设置生存周期的主要目的就是为了防止路由器控制遇到问题发生循环状况时,避免 IP 包无休止的在网络上转发,如下图所示:
这里给大家推荐一款比较好用的追踪超时消息的工具 traceroute,它可以显示出由执行程序的主机到达特定主机之前需要经过多少路由器。 traceroute 的官网如下 http://www.traceroute.org
ICMP 回送消息(类型 0 和 类型 8)
ICMP 回送消息用于判断相互通信的主机之间是否连通,也就是判断所发送的数据包是否能够到达目标主机。可以向对端主机发送回送请求的消息(ICMP Echo Request Message,类型 8),也可以接收对端主机发送来的回送消息(ICMP Echo Reply Message, 类型 0 )。网络上最常用的 ping 命令就是利用这个实现的。
其他 ICMP 消息
ICMP 源点抑制消息(类型 4)
在使用低速率网络的情况下,网络通信可能会遇到网络拥堵的情况下,ICMP 的源点抑制就是为了应对这种情况的。当路由器向低速线路发送数据时,其发送队列的残存数据报变为 0 从而无法发送时,可以向 IP 数据报的源地址发送一个 ICMP 源点抑制(ICMP Source Quench Message) 消息,收到这个消息的主机了解到线路某处发生了拥堵,从而抑制 IP 数据报的发送。
不过这个 ICMP 消息可能会引起不公平的网络通信,一般不被使用。
ICMP 路由器探索消息(类型 9、10)
ICMP 路由器探索消息主要用于路由器发现(Router Discovery, RD),它主要分为两种,路由器请求(Router Solicitation, 类型 10)和路由器响应(Router Advertisement, 类型 9)。主机会在任意路由连接组播的网络上发送一个 RS 消息,想要选择一个路由器进行学习,以此来作为默认路由,而相对应的该路由会发送一个 RA 消息来作为默认路由的响应。
数据包错误消息(KIND=12 CODE=0,1,2)
前提此IP数据包数据是完整的,即校验是通过,否则将丢弃;
- Code=0 通过结构体中的POINTER指针可以指出IP数据包中错误的内容(IP表头+8字节IP数据前8字节)
- Code=1表示参数异常,缺少了必要的参数内容
- Code=2长度错误,长度涉及总长度,IHL长度
ICMP 地址掩码消息(类型 17、18)
主要用于主机或者路由器想要了解子网掩码的情况。可以向那些目标主机或路由器发送 *ICMP 地址掩码请求消息(ICMP Address Mask Request, 类型 17)*和 *ICMP 地址掩码应答消息(ICMP Address Mask Reply, 类型 18)*获取子网掩码信息。
随着 ICMP 的不断更新,很多 ICMP 报文已经不在使用了,这些不再使用的报文类型包括:
信息请求报文和回答报文。
地址掩码请求报文和回答报文。
路由器请求和通告报文。
源点抑制报文。
所以大家只要了解下面这几个 ICMP 报文类型就可以了。
ICMP 报文种类 类型值 报文类型
差错报告报文 3 目标不可达
差错报告报文 5 重定向或路由改变
差错报告报文 11 ICMP 超时
差错报告报文 12 参数问题
查询报文 0 或 8 回送请求或回答
表 9-3
这里需要解释一下这个参数问题,当路由器或者目标主机收到的数据包中的首部字段的值存在问题,就会丢弃数据报,同时发送 ICMP 响应消息。
这里需要注意下,遇到下面这些情况,是不会发送 ICMP 差错报文的。
对具有特殊地址的 IP 比如 127.0.0.1 ,0.0.0.0 是不发送 ICMP 差错报文的。
对具有多播地址的数据报,都不发送 ICMP 报文。
对 ICMP 差错报文,不再发送 ICMP 差错报文。
对第一个分片数据报的后续所有数据报,都不发送 ICMP 差错报文。
ICMPv4 InternetControl Message Protocol Version 4
ICMP不会响应的场景
- 另一个ICMP差错报文(ICMPv4响应报文除外)
- 头部损坏的数据报(例如,校验和错误);所以ICMP处理前提是数据包是完整且正确的。即数据内容可以是错,但是包必需是完整的无错误 对于这类报文将直接丢弃
- IP层目标地址不能为广播/组播数据报
- 链路层广播或是组播的数据报
- 无效或是网络为0的源地址数据报(源地址需为单个主机地址的数据报,源地址不能为0地址,不能为环回地址,不能为广播或是组播地址)
- 除第一个分片外的其他分片数据报
ICMP报文包括以下类型
目标不可到达(类型3):如果路由器判断出不能把P数据报送达目标主机,则向源主机返回这种报文。另一种情况是目标主机找不到有关的用户协议或上层服务访问点,也会返回这种报文。出现这种情况的原因可能是IP头中的字段不正确;或者是数据报中说明的源路由无效;也可能是路由器必须把数据报分段,但IP头中的D标志已置位。
超时(类型11):路由器发现IP数据报的生存期已超时,或者目标主机在一定时间内无法完成重装配,则向源端返回这种报文。
源抑制(类型4):这种报文提供了一种流量控制的初等方式。如果路由器或目标主机缓冲资源耗尽而必须丢弃数据报,则每丢弃一个数据报就向源主机发回一个源抑制报文,这时源主机必须减小发送速度。另外一种情况是系统的缓冲区已用完,并预感到行将发生拥塞,则发出源抑制报文。但是与前一种情况不同,涉及的数据报尚能提交给目标主机。
参数问题(类型12):如果路由器或主机判断出IP头中的字段或语义出错,则返回这种报文,报文头中包含一个指向出错字段的指针。
路由重定向(类型5):路由器向直接相连的主机发出这种报文,告诉主机一个更短的路径。例如路由器R1收到本地网络上主机发来的数据报,R1检查它的路由表,发现要把数据报发往网络X,必须先转发给路由器R2,而R2又与源主机在同一网络中,于是R1向源主机发出路由重定向报文,把R2的地址告诉它。
回声(请求/响应,类型8/0):用于测试两个节点之间的通信线路是否畅通。收到回声请求的节点必须发出回声响应报文。该报文中的标识符和序列号用于匹配请求和响应报文。当连续发出回声请求时,序列号连续递增。常用的PING工具就是这样工作的。
时间戳(请求/响应,类型13/14):用于测试两个节点之间的通信延迟时间。请求方发出本地的发送时间,响应方返回自己的接收时间和发送时间。这种应答过程如果结合强制路由的数据报实现,则可以测量出指定线路上的通信延迟。
地址掩码(请求/响应,类型17/18):主机可以利用这种报文获得它所在的LAN的子网掩码。首先主机广播地址掩码请求报文,同一LAN上的路由器以地址掩码响应报文回答,告诉请求方需要的子网掩码。了解子网掩码可以判断出数据报的目标节点与源节点是否在同一LAN中。
每种差错报文&查询报文类型报文结构
查询报文:
Echo Request
Echo response
ICMP地址掩码请求与应答
ICMP地址掩码请求用于无盘系统在引导过程中获取自己的子网掩码。系统广播ICMP请求报文,类似与RARP获取IP地址;然后无盘系统利用BOOTP协议获取子网掩码。
ICMP地址掩码请求和应答报文的格式如下图:
图片
查询类均有ID&Sequence用来标识,用来标识请求与响应的对应关系
ICMP时间戳请求与应答
ICMP时间戳请求允许系统向另一个系统查询当前的时间。返回的建议值是自午夜开始计算的毫秒数,协调的统一时间(Coordinated Universal Time,UTC)。
ICMP时间戳请求和应答报文格式见下图:
图片
时间戳请求:
在 Internet Control Message Protocol 部分中,Type 值为 13,Code 值为 0,表示该数据包为 ICMP 时间戳请求。
Originate timestamp 的值表示数据包发起的起始时间,这里为 0 秒(午夜 0 点 0 秒);Receive timestamp 的值表示接收数据包的时间,这里为 0 秒;Transmit timestamp 的值表示数据包的发送时间,这里为 0 秒。时间为 0 秒,是因为从午夜零点开始计算。
时间戳响应:
其中,第 7 个数据包为 ICMP 时间戳应答。
在 Internet Control Message Protocol 部分中,Type 值为 14,Code 值为 0,表示该数据包为 ICMP 时间戳应答。
Originate timestamp 的值表示数据包发起的起始时间,这里为 0 秒(午夜零点后开始计算);Receive timestamp 的值表示接收数据包的时间,这里为午夜零点后 8 小时 44 分 24.379 秒;Transmit timestamp 的值表示数据包的发送时间,这里为 31464379 秒,时间为午夜零点后 8 小时 44 分 24.379 秒。
**Originate timestamp:表示请求的时间戳,在请求的时候填入
Receive timestamp:目标主机接收到该Request的时间戳
Transmit timestamp:目标主机回复Reply的发送时间戳
请求主机收到Reply后,记录收到Reply的时间戳,这样可以计算出往返的时长
Receive timestamp-Originate timestamp=Request过程时长
请求主机收到Reply时间戳-Transmit timestamp 响应返回的时长差
**
ICMP端口不可达差错
ICMP端口不可达差错报文包含IP的首部和产生ICMP差错报文的IP数据报的前8字节。主要是因为IP首部包含协议字段,使得ICMP知道如何解释后面8个字节。
ICMP不可达报文的一般格式见下图:
图片
ICMP 参数错误报告的报文格式
报告“参数问题”的 ICMP 报文,Type = 12,有两个 Code(0和1),其报文格式,与图4-105有所不同,如图4-106所示:
与 ICMP 错误报告的基本格式相比,参数错误报告,多了1个“指针”字段(占用8个 bits,1个字节)。指针(Pointer)字段与报文的中代码(Code)字段相关。
当 Code = 0 时,其意味着原报文的 IP Header 里面某个参数出现了错误(包括固定IP Header 和 IP Header Option),此时 Pointer 字段就代表是第几个字节出现了错误(序号从0开始)。比如原报文中的 ToS 字段出现了错误,那么 Pointer 就等于 1。
当 Code = 1 时,其意味着原报文的 IP Header 里面缺少某个参数(当然,也只能是 IP Header Option 里缺少某个参数,而接收端又恰好需要)。此时,Pointer 字段没有意义,全设置为0。这也就意味着,到底缺少哪个参数——对不起,不告诉你,你去猜吧,_。
需要强调的是,无论是 Code 等于0还是1,作为接收端,路由器和主机都可能会发送该 ICMP 报文,而且对于原 IP 报文,它们也都会将其丢弃。
CAPL脚本测试实现
除了ICMP标准头部(类型+Code+CheckSum)后续的所有内容均为ICMP的数据,SetData时候设置ICMP标准头后面的所有数据内容,故要注意Offset偏移
echoRequest&EchoReply
msg.icmpv4.echoReply.Init();
msg.icmpv4.echoReply.identifier=1;
msg.icmpv4.echoReply.sequence=0x1223;
msg.icmpv4.echoReply.SetData(4,time,20);
Timestamp请求与回复
单位为ms;请求的时候只需设置timestampOriginate,回复的时候由目标主机设置接收与发送的时间戳。通过timestampReceive-timestampOriginate可以计算出发送的路径传输时长,Request主机收到TimestampReply时间戳-timestampTransmit可以计算出返回传输路径的时长
msg.icmpv4.timestamp.Init();
msg.icmpv4.timestamp.timestampOriginate=1*60*60*1000+5*60*1000+58*1000;
msg.icmpv4.timestamp.timestampReceive=0x0000;
msg.icmpv4.timestamp.timestampTransmit=0x0000;
参数错误报文合成
- 参数错误返回时含相应的IP数据报内容=IP包全部数据+数据报前8字节数据
- 脚本设置数据域内容时候;如果要跳过Pointer参数的设置,需偏移4字节
msg.icmpv4.parameterProblem.Init();
msg.icmpv4.parameterProblem.pointer=0x05;
msg.icmpv4.parameterProblem.SetData(4,time,20);
路由重定向错误报文
只有包含一组IP地址
msg.icmpv4.redirect.Init();
msg.icmpv4.redirect.gatewayAddress.SetData(0,time,4);
网络MASK请求
MASK请求的时候,MASK值设置为0 回复的时候由目标主机填入
msg.icmpv4.addrMaskRequest.Init();
msg.icmpv4.addrMaskRequest.identifier=1;
msg.icmpv4.addrMaskRequest.sequence=1234;
msg.icmpv4.addrMaskRequest.addressMask.SetData(0,time,4);
ICMP各错误场景如何处理
网络不可达
触发方式:当一个IP数据包无法到达目的地时,路由器会向源地址发送一个ICMP“目标不可达”消息。这通常发生在目标网络不存在或无法访问的情况下。
主机不可达
触发方式:当数据包到达目标网络后,发现目标主机无法访问(如主机关机、网络故障等),会生成主机不可达的ICMP错误消息。
协议不可达
触发方式:当数据包到达目标主机后,发现无法处理该数据包所使用的协议(如目标主机未运行相应的服务或协议栈不支持该协议),将发送协议不可达的ICMP错误消息。
端口不可达
触发方式:当数据包到达目标主机后,发现无法到达目标端口(如端口未开放、被防火墙拦截等),会产生端口不可达的ICMP错误消息。
需要分片但设置不允许分片
触发方式:当数据包太大而需要在传输过程中进行分片,但发现目标主机或路由器不允许分片(如MTU限制),将发送相应的ICMP错误消息。
传输期间生存时间为零
触发方式:数据包在传输过程中经过多个路由器,并且生存时间(TTL,Time to Live)逐渐减少。如果数据包因为生存时间为零而被丢弃,会生成传输期间生存时间为零的ICMP错误消息。
ICMP 超时报错
触发方式:
数据包在传输过程中丢失:数据包可能因为路由器故障、链路故障或其他原因导致丢失。
目的地不可达:数据包尝试到达一个不存在的IP地址或网络设备。
路由器超时:数据包经过一个或多个路由器时,如果在规定的时间内未能到达下一个路由器。
ICMP 报文类型:对于超时报错,ICMP 报文的类型字段值为11,代码字段值为0。
IP 头部包含错误选项
触发方式:当IP数据包头部包含了选项字段,但选项字段的格式不正确时,会产生参数问题的ICMP错误消息。
网络重定向和主机重定向
触发方式:
网络重定向:路由器可以发送网络重定向的ICMP错误消息,告诉主机将数据包发送到更佳的网络路径。
主机重定向:类似于网络重定向,但是告知主机发送到更佳的主机路径。
总结
ICMP错误场景的触发通常与数据包在网络中的传输问题相关,包括目标不可达、协议不匹配、端口未开放、数据包过大需要分片但不允许、生存时间耗尽、数据包丢失或超时等。这些错误消息为网络管理和故障排除提供了重要信息。在实际应用中,网络管理员可以根据ICMP错误消息快速定位问题并采取相应的解决措施。
TCP包传输过程会触发哪些ICMP错误
TCP包在传输过程中可能会触发多种ICMP(Internet Control Message Protocol,互联网控制消息协议)错误。这些错误通常与TCP包的传输问题相关,包括目标不可达、路由问题、数据包大小问题以及网络拥塞等。以下是一些TCP包可能触发的##### ICMP错误:
- 目标不可达(Destination Unreachable):
- 主机不可达(Host Unreachable):当TCP包无法到达指定的目标主机时,会触发此错误。这可能是因为目标主机已关闭、网络故障或路由问题。
- 网络不可达(Network Unreachable):当TCP包无法到达目标网络时,会触发此错误。这通常意味着目标网络不存在或无法访问。
- 协议不可达(Protocol Unreachable):如果目标主机不支持TCP包所使用的协议,则会触发此错误。然而,由于TCP是互联网的核心协议之一,这种情况较为罕见。
- 端口不可达(Port Unreachable):当TCP包到达目标主机但目标端口未开放或无法访问时,会触发此错误。这通常是因为没有服务在监听该端口。
- 源站抑制(Source Quench):
这是一个较老的ICMP消息类型,用于通知发送方降低发送速率,以防止网络拥塞。然而,在现代网络中,源站抑制消息的使用已经很少,因为许多现代路由器和交换机使用更复杂的拥塞控制机制。 - 超时/超期(Time Exceeded):
如果TCP包在传输过程中由于生存时间(TTL)耗尽而被丢弃,则可能会触发超时/超期的ICMP错误。这通常意味着数据包在网络中经过了过多的跳数(hop),或者路由路径存在问题。 - 参数问题(Parameter Problem):
如果TCP包的IP头部包含错误的选项或参数,则可能会触发参数问题的ICMP错误。这通常是由于数据包格式错误或配置问题导致的。 - 重定向(Redirect):
重定向消息虽然不直接指示错误,但它是ICMP消息的一种,用于指示发送方使用更好的路由路径。在TCP包传输过程中,如果路由器发现更优的路由路径,可能会向发送方发送重定向消息。
需要注意的是,并不是所有TCP包传输过程中的问题都会触发ICMP错误。有些问题可能只是导致TCP连接超时、重传或断开连接,而不会生成ICMP错误消息。此外,由于网络环境和配置的不同,某些ICMP错误可能不会在所有情况下都触发。
在实际应用中,网络管理员和开发人员可以通过分析ICMP错误消息来诊断和解决TCP包传输过程中出现的问题。然而,也需要注意ICMP消息的局限性和可能的安全风险(如ICMP洪水攻击),并采取相应的安全措施来保护网络免受攻击。
DHCP动态主机配置协议
DHCP地址分配类型
- 动态分配:即DHCP服务器动态分布IP地址,且该地址超时将撤消
- 自动分配:即DHCP服务器为每个客户端分配一随机地址,但是该地址将无限期使用
- 手动分配:为特定的客户端配置特定的IP地址,不会随机选址,且不能撤消
DHCP消息格式
各字段的长度固定,
- Op:标识消息是请求消息(1)还是应答消息(2)&仅能选择此两个值 从CLIENT发出的均是请求,从SERVER发送均为应答;
- HW类型:硬件类型,基于ARP使用的值,对于以太网,该值为1;
- HW长度:存放硬件(MAC)地址的长度,对于以太网MAC地址,该值为6;
- 跳步数:保存消息传输过程中的中继次数。消息发送方将该值设置为0,并在每次中继时递增;所以该值是由响应服务器填充并返回给客户端
- 事务ID:由客户机选择的随机数,服务器将它复制到响应中,用于将请求和应答匹配起来;RR请求用来表示请求与响应的对应关系
- 秒数:由客户机设置,它是第一次尝试申请或重新申请地址经过的秒数;首次申请该值为0,重新申请的时候,该值是相对于
- 标志:该字段16位中,目前只用了最高1位,称为广播标志。客户机可以在请求中设置该位,表示它们不能或不愿处理单播IP数据报,但可处理广播数据报(例如,客户机还没有IP地址的情况)。通过设置该位通知服务器和中继代理,广播地址可用于响应中。
- ciaddr:如果客户机已有IP地址的话,客户机在发送请求时将自己的IP地址放在此处;**存放客户端当前使用过或是正在使用的IP值,如果无IP值,用0填充 **
- yiaddr:由服务器填写,服务器把想要分配给客户机的IP地址放在此处;
- siaddr:一般是DHCP服务器的IP地址;
- giaddr/agentAddr:如果需要跨子网进行DHCP地址分配(DHCP服务器与客户机不在同一子网),则在此处填写经过的路由器的IP地址;
- chaddr:客户机的硬件地址,即MAC地址;用来标识客户端,MAC是唯一,即让服务器知道该IP分配给谁,同时也可用于指导服务分配给客户端何地址,比如在手动分配或是自动化配支起的情况一种对应关系的KEY值
- sname:并非每次都要填写,表示服务器名;
- file:并非每次都要填写,表示启动文件路径;通过DHCP的选项值,可以决定此两个字段用于存储选项数据值
- 选项:常见选项见下。
各字段填充要求
ciaddr作用与填充规则
- 在没有获取有效IP前,该值将一直保持为0.0.0.0
- 在已经获取有效IP,并能够正常使用时候,DHCPREQUEST时候,ciaddr填充为当前使用的IP值
siaddr作用与填充规则
- 在回复OFFER与ACK过程填充服务器自身的IP地址
- 在未获取IP前,请求需填充此字段表明请求的服务器标识,同时选项中也需包含51选项,指明选择的服务器
- 在获取IPe且启用该IP后的请求,将填充有效的服务地址,但是选项中不包含相应的服务器选项
magic Cookie字段意义
如果该字段值为OK即(0x63825363)即表示该报文为DHCP报文,而非BOOTP报文,将启用后续的选项内容!选项内容在CAPL脚本无相应的直接添加接口,需使用如下方式进行添加:
即通过上层协议UDP的数据域内容添加方式进行添加,也可以使用DHCP头部数据内容方式进行添加操作
DHCP服务器配置界面
向客户端提供IP地址,网关地址,DNS服务器地址,及租期等基础信息
IP地址获取失败处理方式
获取 IP 失败,则给自己配置一个临时 IP:169.254.0.0/16 全球统一的无效 IP ,用于内网临时通信使用。
DHCP 如何分配地址(消息交互流程)
如下图,是客户端接入网络时发生的消息交互流程:
on key 'p'
{
byte mac[6]={15,25,36,35,39,25};
byte opt1[200]={0x35,0x01,0x01,0x36,4,192,168,25,66,0xFF};
syn_packet.Clear();
syn_packet.Clear();
syn_packet.dhcpv4.Init();
syn_packet.dhcpv4.magicCookie.Init();
//syn_packet.dhcpv4.magicCookie.Init();
syn_packet.CompletePacket();
syn_packet.dhcpv4.clientHwAddr.SetData(0,mac,6);
syn_packet.dhcpv4.xid=random(0xFFFFFFFF);
syn_packet.dhcpv4.time=0x100;
syn_packet.dhcpv4.flags|=0x8000;
//要先调整大小才能往里面加数据
//syn_packet.udp.ResizeData(syn_packet.dhcpv4.header.byteLength+6);
syn_packet.dhcpv4.header.SetData(syn_packet.dhcpv4.header.byteLength,opt1,10);
syn_packet.CompletePacket();
//this.msgChannel=1;
output(syn_packet);
}
DHCP状态机
DHCP&BOOTP区别
DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户机能够利用这个IP上网。
DHCP前身是BOOTP,在Linux的网卡配置中也能看到显示的是BOOTP,DHCP引进一个bootp没有的概念:租约。bootp分配的地址是永久的,而dhcp分配的地址是可以有期限的。
DHCP作用及特点
DHCP可以自动分配IP、子网掩码、网关、DNS。
DHCP客户端使用的端口68,服务端使用端口67,使用的UDP应用层的协议。
DHCP一般不为服务器分配IP,因为他们要使用固定IP,所以DHCP一般只为办公环境的主机分配IP。
DHCP服务器和客户端需要在一个局域网内,在为客户端分配IP的时候需要进行多次广播。**但DHCP也可以为其他网段内主机分配IP,只要连接两个网段中间的路由器能转发DHCP配置请求即可,但这要求路由器配置中继功能。**路由是通过IP来识别转发的,所以此时要结合协议与IP来组合判断转发!
DHCP服务器IP分配三种方式
1)自动分配(Automatic Allocation)(MAC地址与IP绑定)
自动分配是当DHCP客户端第一次成功地从DHCP服务器端分配到一个IP地址之后,就永远使用这个地址。
2)动态分配(Dynamic Allocation)常用方式
动态分配是当DHCP客户端第一次从DHCP服务器分配到IP地址后,并非永久地使用该地址,每次使用完后,DHCP客户端就得释放这个IP地址,以给其他客户端使用。
3)手动分配
手动分配是由DHCP服务器管理员专门为客户端指定IP地址。
区别:
1、自动分配和手动分配都是分配静态ip
2、自动分配需要在配置文件中配置IP与MAC对应关系,在在静态表中,获取IP必须通过DHCP服务器
3、手动分配需要人工操作,不需要通过DHCP服务器
4、动态分配有时效性
DHCP协议报文类型
(1)Discover:DHCP客户端首次登录网络时进行DHCP交互过程发送的第一个数据包, 用来寻找DHCP服务器;RequestID=1 DHCPDISCOVER
(2)Offer:DHCP服务器用来响应DHCP Discover报文,此报文携带了各种配置信息;RequestID=2 DHCPOFFER
(3)Request:
-客户端初始化后,发送广播的DHCP Request报文来回应服务器的DHCP Offer报文;RequestID=3 DHCPREQUEST
-客户端重启初始化后,发送广播的DHCP Request报文来确认先前被分配的IP地址等信息;RequestID=3 DHCPREQUEST
-当客户端已经和某个IP地址绑定后,发送DHCP Request单播或者广播报文来更新IP 地址租约;
(4)ACK:服务器对客户端的DHCP Request报文的确认响应报文,客户端收到此报文后,才真正获得了IP地址和相关的信息;RequestID=5 DHCPACK
(5)NAK:服务器对客户端的DHCP Request报文的拒绝响应报文,告知无法分配合适的IP地址;RequestID=6 DHCPNACK
(6)Decline【拒绝,谢绝】:当客户端发现服务器分配给他的IP地址发生冲突时会通过发送此报文来通知服务器,并且会重新申请地址;RequestID=4 DHCDECLINE
(7)Release:客户端可以通过此报文主动释放服务器分配的IP地址;RequestID=7 DHCPRelease
Release 报文的作用:是释放使用的地址,让 DHCP 服务器收回该地址,可以分配给其它设备使用。该报文使用已获取的地址作为源地址,以 255.255.255.255 为广播地址 进行发送。
(8)Inform:DHCP客户端获取IP地址后,如果需要向服务器获取更详细的配置信息(网关信息、DNS地址),发送此报文;RequestID=8 DHCPINFORM
无中继场景时DHCP客户端首次接入网络的工作原理
如下图所示,在没有部署DHCP中继的场景下,首次接入网络DHCP客户端与DHCP服务器的报文交互过程,该过程称为DHCP报文四步交互。
第一步:发现阶段
首次接入网络的DHCP客户端不知道DHCP服务器的IP地址,为了学习到DHCP服务器的IP地址,DHCP客户端以广播方式发送DHCP DISCOVER报文(目的IP地址为255.255.255.255)给同一网段内的所有设备(包括DHCP服务器或中继)。DHCP DISCOVER报文中携带了客户端的MAC地址等信息。
- 当DHCP客户机第一次登录网络的时候(也就是客户机上没有任何IP地址数据时),它会通过UDP 67端口向网络上发出一个DHCPDISCOVER数据包(包中包含客户机的MAC地址和计算机名等信息)。因为客户机还不知道自己属于哪一个网络,所以封包的源地址为0.0.0.0,目标地址为255.255.255.255,然后再附上DHCP discover的信息,向网络进行广播。
- DHCP discover的等待时间预设为1秒,也就是当客户机将第一个DHCP discover封包送出去之后,在1秒之内没有得到回应的话,就会进行第二次DHCP discover广播。若一直没有得到回应,客户机会将这一广播包重新发送四次(以2,4,8,16秒为间隔,加上1-1000毫秒之间随机长度的时间)。如果都没有得到DHCP Server的回应,客户机会从169.254.0.0/16这个自动保留的私有IP地址中选用一个IP地址。并且每隔5分钟重新广播一次,如果收到某个服务器的响应,则继续IP租用过程。
第二步:提供阶段
与DHCP客户端位于同一网段的DHCP服务器都会接收到DHCP DISCOVER报文,DHCP服务器选择跟接收DHCP DISCOVER报文接口的IP地址处于同一网段的地址池,并且从中选择一个可用的IP地址,然后通过DHCP OFFER报文发送给DHCP客户端。
通常,DHCP服务器的地址池中会指定IP地址的租期,如果DHCP客户端发送的DHCP DISCOVER报文中携带了期望租期,服务器会将客户端请求的期望租期与其指定的租期进行比较,选择其中时间较短的租期分配给客户端。
DHCP服务器在地址池中为客户端分配IP地址的顺序如下:
(1)DHCP服务器上已配置的与客户端MAC地址静态绑定的IP地址。
(2)客户端发送的DHCP DISCOVER报文中Option50(请求IP地址选项)指定的地址。
(3)地址池内查找“Expired”状态的IP地址,即曾经分配给客户端的超过租期的IP地址。
(4)在地址池内随机查找一个“Idle”状态的IP地址。
(5)如果未找到可供分配的IP地址,则地址池依次自动回收超过租期的(“Expired”状态)和处于冲突状态(“Conflict”状态)的IP地址。回收后如果找到可用的IP地址,则进行分配;否则,DHCP客户端等待应答超时后,重新发送DHCP DISCOVER报文来申请IP地址。
设备支持在地址池中排除某些不能通过DHCP机制进行分配的IP地址。例如,客户端所在网段已经手工配置了地址为192.168.1.100/24的DNS服务器,DHCP服务器上配置的网段为192.168.1.0/24的地址池中需要将192.168.1.100的IP地址排除,不能通过DHCP分配此地址,否则,会造成地址冲突。
为了防止分配出去的IP地址跟网络中其他客户端的IP地址冲突,DHCP服务器在发送DHCP OFFER报文前通过发送源地址为DHCP服务器IP地址、目的地址为预分配出去IP地址的ICMP ECHO REQUEST报文对分配的IP地址进行地址冲突探测。如果在指定的时间内没有收到应答报文,表示网络中没有客户端使用这个IP地址,可以分配给客户端;如果指定时间内收到应答报文,表示网络中已经存在使用此IP地址的客户端,则把此地址列为冲突地址,然后等待重新接收到DHCP DISCOVER报文后按照前面介绍的选择IP地址的优先顺序重新选择可用的IP地址。
此阶段DHCP服务器分配给客户端的IP地址不一定是最终确定使用的IP地址,因为DHCP OFFER报文发送给客户端等待16秒后如果没有收到客户端的响应,此地址就可以继续分配给其他客户端。通过下面的选择阶段和确认阶段后才能最终确定客户端可以使用的IP地址。
第三步:选择阶段
如果有多个DHCP服务器向DHCP客户端回应DHCP OFFER报文,则DHCP客户端一般只接收第一个收到的DHCP OFFER报文,然后以广播方式发送DHCP REQUEST报文,该报文中包含客户端想选择的DHCP服务器标识符(即Option50,填充了接收的DHCP OFFER报文中yiaddr字段的IP地址)。
DHCP客户端广播发送DHCP REQUEST报文通知所有的DHCP服务器,它将选择某个DHCP服务器提供的IP地址,其他DHCP服务器可以重新将曾经分配给客户端的IP地址分配给其他客户端。
此时,由于还没有得到DHCP Server的最后确认,客户端仍然使用0.0.0.0为源IP地址,255.255.255.255为目标地址进行广播。
第四步:确认阶段
当DHCP服务器收到DHCP客户端发送的DHCP REQUEST报文后,DHCP服务器以广播形式回应DHCP ACK报文,表示DHCP REQUEST报文中请求的IP地址(Option50填充的)分配给客户端使用。
DHCP客户端收到DHCP ACK报文,会广播发送免费ARP报文,探测本网段是否有其他终端使用服务器分配的IP地址,如果在指定时间内没有收到回应,表示客户端可以使用此地址。如果收到了回应,说明有其他终端使用了此地址,客户端会向服务器发送DHCP DECLINE报文,并重新向服务器请求IP地址,同时,服务器会将此地址列为冲突地址。当服务器没有空闲地址可分配时,再选择冲突地址进行分配,尽量减少分配出去的地址冲突。
当DHCP服务器收到DHCP客户端发送的DHCP REQUEST报文后,如果DHCP服务器由于某些原因(例如协商出错或者由于发送REQUEST过慢导致服务器已经把此地址分配给其他客户端)无法分配DHCP REQUEST报文中Option50填充的IP地址,则发送DHCP NAK报文作为应答,通知DHCP客户端无法分配此IP地址。DHCP客户端需要重新发送DHCP DISCOVER报文来申请新的IP地址。
有中继场景时DHCP客户端首次接入网络的工作原理
有DHCP中继的场景中,首次接入网络的DHCP客户端和DHCP服务器的工作原理与无中继场景时DHCP客户端首次接入网络的工作原理相同。主要差异是DHCP中继在DHCP服务器和DHCP客户端之间转发DHCP报文,以保证DHCP服务器和DHCP客户端可以正常交互。下面仅针对DHCP中继的工作原理进行介绍。
如下图所示,在部署DHCP中继的场景下,首次接入网络DHCP客户端与DHCP服务器的报文交互过程。
第一步:发现阶段
DHCP中继接收到DHCP客户端广播发送的DHCP DISCOVER报文后,进行如下处理:
(1)检查DHCP报文中的hops字段,如果大于16,则丢弃DHCP报文;否则,将hops字段加1(表明经过一次DHCP中继),并继续下面的操作。
(2)检查DHCP报文中的giaddr字段。如果是0,将giaddr字段设置为接收DHCP DISCOVER报文的接口IP地址。如果不是0,则不修改该字段,继续下面的操作。检查DHCP报文中的giaddr字段。DHCP报文中的giaddr字段标识客户端网关的IP地址。如果服务器和客户端不在同一个网段且中间存在多个DHCP中继,当客户端发出DHCP请求时,第一个DHCP中继会把自己的IP地址填入此字段,后面的DHCP中继不修改此字段内容。DHCP服务器会根据此字段来判断出客户端所在的网段地址,从而为客户端分配该网段的IP地址。
(3)将DHCP报文的目的IP地址改为DHCP服务器或下一跳中继的IP地址,源地址改为中继连接客户端的接口地址,通过路由转发将DHCP报文单播发送到DHCP服务器或下一跳中继。
如果DHCP客户端与DHCP服务器之间存在多个DHCP中继,后面的中继接收到DHCP DISCOVER报文的处理流程同前面所述。
第二步:提供阶段
DHCP服务器接收到DHCP DISCOVER报文后,选择与报文中giaddr字段为同一网段的地址池,并为客户端分配IP地址等参数,然后向giaddr字段标识的DHCP中继单播发送DHCP OFFER报文。
DHCP中继收到DHCP OFFER报文后,会进行如下处理:
(1)检查报文中的giaddr字段,如果不是接口的地址,则丢弃该报文;否则,继续下面的操作。
(2)DHCP中继检查报文的广播标志位。如果广播标志位为1,则将DHCP OFFER报文广播发送给DHCP客户端;否则将DHCP OFFER报文单播发送给DHCP客户端。
第三步:选择阶段
中继接收到来自客户端的DHCP REQUEST报文的处理过程同无中继场景下的选择阶段。
第四步:确认阶段
中继接收到来自服务器的DHCP ACK报文的处理过程同无中继场景下的确认阶段。
DHCP客户端重用曾经使用过的地址的工作原理(重启等场景)
DHCP客户端非首次接入网络时,可以重用曾经使用过的地址。如下图所示,DHCP客户端与DHCP服务器交互DHCP报文,以重新获取之前使用的IP地址等网络参数,该过程称为两步交互。
第一步:选择阶段
客户端广播发送包含前一次分配的IP地址的DHCP REQUEST报文,报文中的Option50(请求的IP地址选项)字段填入曾经使用过的IP地址。
第二步:确认阶段
DHCP服务器收到DHCP REQUEST报文后,根据DHCP REQUEST报文中携带的MAC地址来查找有没有相应的租约记录,如果有则返回DHCP ACK报文,通知DHCP客户端可以继续使用这个IP地址。否则,保持沉默,等待客户端重新发送DHCP DISCOVER报文请求新的IP地址。
DHCP客户端更新租期示意图
(1)当租期达到50%(T1)时,DHCP客户端会自动以单播的方式向DHCP服务器发送DHCP REQUEST报文,请求更新IP地址租期。如果收到DHCP服务器回应的DHCP ACK报文,则租期更新成功(即租期从0开始计算);如果收到DHCP NAK报文,则重新发送DHCP DISCOVER报文请求新的IP地址。
(2)当租期达到87.5%(T2)时,如果仍未收到DHCP服务器的应答,DHCP客户端会自动以广播的方式向DHCP服务器发送DHCP REQUEST报文,请求更新IP地址租期。如果收到DHCP服务器回应的DHCP ACK报文,则租期更新成功(即租期从0开始计算);如果收到DHCP NAK报文,则重新发送DHCP DISCOVER报文请求新的IP地址。
确认问题:因为此时IP为可用状态,所以广播时候,源IP不能为全0,填充内容与50%时候更新请求报文内容一致
(3)如果租期时间到时都没有收到服务器的回应,客户端停止使用此IP地址,重新发送DHCP DISCOVER报文请求新的IP地址。
客户端在租期时间到之前,如果用户不想使用分配的IP地址(例如客户端网络位置需要变更),会触发DHCP客户端向DHCP服务器发送DHCP RELEASE报文,通知DHCP服务器释放IP地址的租期。DHCP服务器会保留这个DHCP客户端的配置信息,将IP地址列为曾经分配过的IP地址中,以便后续重新分配给该客户端或其他客户端。客户端可以通过发送DHCP INFORM报文向服务器请求更新配置信息。
如下图所示,部署DHCP中继时,更新租期的过程与上述过程相似。
填充选项&结束选项域名Code=1
选项的长度不包含Code与长度本身 只表示选项参数的长度
HEX:00&FF 占一个BYTE空间,无LEN选项 00填充 FF用于结束
子网掩码
如果在 DHCP 回复中同时指定了子网掩码和路由器选项,则必须首先指定子网掩码选项
Kind=1 Length=4 Data=MASK
时间偏移域名Code=2
时间偏移字段以秒为单位指定客户端子网与协调世界时(Coordinated Universal Time,UTC) 的偏移量。 偏移量表示为二进制补码 32 位整数。 正偏移表示零子午线以东的位置,负偏移表示零子午线以西的位置。
时间偏移选项的代码为 2,其长度为 4 个八位字节。
路由器选项实际即为网关的IP地址域名Code=3
路由器选项指定客户端子网上路由器的 IP 地址列表。 路由器应该按优先顺序列出。
路由器选项的代码是 3。路由器选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。数量可变,但需为4字节倍数
时间服务器选项域名Code=4
时间服务器选项指定客户端可用的 RFC 868 [6] 时间服务器列表。 服务器应该按优先顺序列出。
时间服务器选项的代码是 4。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
域名服务器选项域名Code=6
域名服务器选项指定客户端可用的域名系统(STD 13,RFC 1035 [8])名称服务器列表。 服务器应该按优先顺序列出。
域名服务器选项的代码是 6。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
日志服务器选项域名Code=7
日志服务器选项指定客户端可用的 MIT-LCS UDP 日志服务器列表。 服务器应该按优先顺序列出。
日志服务器选项的代码是 7。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
Cookie 服务器选项域名Code=8
cookie 服务器选项指定客户端可用的 RFC 865 [9] cookie 服务器列表。 服务器应该按优先顺序列出。
日志服务器选项的代码是 8。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
LPR 服务器选项域名Code=9
LPR 服务器选项指定客户端可用的 RFC 1179 [10] 行式打印机服务器列表。 服务器应该按优先顺序列出。
LPR 服务器选项的代码是 9。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
Impress服务器选项域名Code=10
Impress 服务器选项指定客户端可用的 Imagen Impress 服务器列表。 服务器应该按优先顺序列出。
Impress 服务器选项的代码是 10。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
资源位置服务器选项域名Code=11
此选项指定客户端可用的 RFC 887 [11] 资源位置服务器列表。 服务器应该按优先顺序列出。
这个选项的代码是 11。这个选项的最小长度是 4 个八位字节,并且长度必须始终是 4 的倍数。
主机名选项域名Code=12
此选项指定客户端的名称。 该名称可能会或可能不会被本地域名限定(有关检索域名的首选方式,请参阅第 3.17 节)。 有关字符集限制,请参阅 RFC 1035。
此选项的代码为 12,其最小长度为 1。
启动文件大小选项域名Code=13
此选项指定客户端默认引导映像的 512 个八位字节块的长度。 文件长度被指定为一个无符号的 16 位整数。
此选项的代码为 13,长度为 2。
优点转储文件域名Code=14
此选项指定在客户端崩溃时应将客户端的核心映像转储到的文件的路径名。 路径被格式化为由 NVT ASCII 字符集中的字符组成的字符串。
此选项的代码为 14。其最小长度为 1。
域名Code=15
此选项指定客户端在通过域名系统解析主机名时应使用的域名。
此选项的代码为 15。其最小长度为 1。
交换服务器Code=16
这指定了客户端交换服务器的 IP 地址。
此选项的代码为 16,长度为 4。
根路径Code=17
此选项指定包含客户端根磁盘的路径名。 路径被格式化为由 NVT ASCII 字符集中的字符组成的字符串。
此选项的代码为 17。其最小长度为 1。
最大数据报重组大小根路径Code=22
此选项指定客户端应准备重新组装的最大数据报大小。 大小指定为 16 位无符号整数。 最小值合法值为 576。
此选项的代码为 22,长度为 2。
默认 IP 生存时间Code=23
此选项指定客户端应在传出数据报上使用的默认生存时间。 TTL 被指定为一个八位字节,其值在 1 到 255 之间。
此选项的代码为 23,长度为 1。
路径 MTU 老化超时选项
此选项指定在 RFC 1191 [12] 中定义的机制发现的老化路径 MTU 值时使用的超时(以秒为单位)。 超时指定为 32 位无符号整数。
此选项的代码为 24,长度为 4。
广播地址选项
此选项指定在客户端子网上使用的广播地址。 广播地址的合法值在 [4] 的第 3.2.1.3 节中指定。
此选项的代码为 28,长度为 4。
执行掩码发现选项
此选项指定客户端是否应使用 ICMP 执行子网掩码发现。 值 0 表示客户端不应执行掩码发现。 值为 1 表示客户端应该执行掩码发现。
此选项的代码为 29,长度为 1。
TCP 保活间隔选项
此选项指定客户端 TCP 在 TCP 连接上发送 keepalive 消息之前应等待的时间间隔(以秒为单位)。 时间指定为 32 位无符号整数。 零值表示客户端不应在连接上生成保活消息,除非应用程序特别请求。
此选项的代码为 38,长度为 4。
TCP Keepalive 垃圾选项
此选项指定客户端是否应发送带有垃圾八位字节的 TCP keepalive 消息以与旧实现兼容。 值 0 表示不应发送垃圾八位字节。 值为 1 表示应发送垃圾八位字节。
此选项的代码为 39,长度为 1。
请求的 IP 地址
此选项用于客户端请求 (DHCPDISCOVER) 以允许客户端请求分配特定 IP 地址。客户端期望使用的IP地址信息,或是请求使用的IP地址当DISCOVER信息中携带此Option消息,表示Client期望使用此地址,如果服务器发现此地址可以为其使用,可以直接使用快速确认方式即跳过OFFER等过程,直接发ACK确认此消息
此选项的代码为 50,长度为 4。
IP地址租用时间
此选项用于客户端请求(DHCPDISCOVER 或 DHCPREQUEST)以允许客户端请求 IP 地址的租用时间。 在服务器回复 (DHCPOFFER) 中,DHCP 服务器使用此选项来指定它愿意提供的租用时间。
时间以秒为单位,并指定为 32 位无符号整数。
此选项的代码为 51,长度为 4。
选项过载
此选项用于指示 DHCP ‘sname’ 或 ‘file’ 字段通过使用它们来承载 DHCP 选项而过载。 如果返回的参数将超出为选项分配的通常空间,则 DHCP 服务器会插入此选项。
如果存在此选项,则客户端会在结束对标准选项字段的解释后解释指定的附加字段。
此选项的代码为 52,长度为 1。此选项的合法值为:
DHCP 消息类型
此选项用于传达 DHCP 消息的类型。 此选项的代码为 53,其长度为 1。此选项的合法值为:
服务器标识符
此选项用于 DHCPOFFER 和 DHCPREQUEST 消息中,并且可以选择性地包含在 DHCPACK 和 DHCPNAK 消息中。 DHCP 服务器在 DHCPOFFER 中包含此选项,以允许客户端区分租用提议。 DHCP 客户端使用“服务器标识符”字段的内容作为任何单播到 DHCP 服务器的 DHCP 消息的目标地址。 DHCP 客户端还通过在 DHCPREQUEST 消息中包含此选项来指示正在接受哪些租用提议。
标识符是所选服务器的 IP 地址。
此选项的代码为 54,长度为 4。
参数请求列表
DHCP 客户端使用此选项来请求指定配置参数的值。 请求的参数列表指定为 n 个八位字节,其中每个八位字节是本文档中定义的有效 DHCP 选项代码。
客户端可以按优先顺序列出选项。 DHCP 服务器不需要按照请求的顺序返回选项,但必须尝试按照客户端请求的顺序插入请求的选项。
此选项的代码为 55。其最小长度为 1。
消息
DHCP 服务器使用此选项在发生故障时通过 DHCPNAK 消息向 DHCP 客户端提供错误消息。 客户端可以在 DHCPDECLINE 消息中使用此选项来指示客户端拒绝提供的参数的原因。 该消息由 n 个八位字节的 NVT ASCII 文本组成,客户端可以在可用的输出设备上显示这些文本。
此选项的代码为 56,其最小长度为 1。
最大 DHCP 消息大小
此选项指定它愿意接受的最大长度 DHCP 消息。 长度被指定为一个无符号的 16 位整数。 客户端可以在 DHCPDISCOVER 或 DHCPREQUEST 消息中使用最大 DHCP 消息大小选项,但不应在 DHCPDECLINE 消息中使用该选项。
此选项的代码为 57,其长度为 2。最小合法值为 576 个八位字节。
续订 (T1) 时间值
此选项指定从地址分配到客户端转换到 RENEWING 状态的时间间隔。
该值以秒为单位,并指定为 32 位无符号整数。
此选项的代码为 58,长度为 4。
新绑定 (T2) 时间值
此选项指定从地址分配到客户端转换到 REBINDING 状态的时间间隔。
该值以秒为单位,并指定为 32 位无符号整数。
此选项的代码为 59,长度为 4。
厂商类别标识符
DHCP 客户端使用此选项来选择性地识别 DHCP 客户端的厂商类型和配置。 该消息是一个由 n 个八位字节组成的字符串,由服务器解释。 厂商可以选择定义特定的厂商类别标识符来传达有关客户端的特定配置或其他标识消息。 例如,标识符可以对客户端的硬件配置进行编码。 不具备解释客户端发送的特定于类的消息的能力的服务器必须忽略它(尽管它可能会被报告)。 响应的服务器应该只使用选项 43 将特定于厂商的消息返回给客户端。
此选项的代码为 60,其最小长度为 1。
客户标识符
DHCP 客户端使用此选项来指定其唯一标识符。 DHCP 服务器使用这个值来索引它们的地址绑定数据库。对于管理域中的所有客户端,该值应该是唯一的。
标识符应该被 DHCP 服务器视为不透明的对象。
客户端标识符可以由类似于 [3] 中定义的“htype”/“chaddr”字段的类型-值对组成。例如,它可以由硬件类型和硬件地址组成。在这种情况下,类型字段应该是 STD2 [22] 中定义的 ARP 硬件类型之一。当值字段包含硬件地址以外的标识符(例如,完全限定域名)时,应使用硬件类型 0(零)。
为了正确识别客户端,每个客户端的客户端标识符在客户端所连接的子网上使用的客户端标识符中必须是唯一的。厂商和系统管理员负责选择满足此唯一性要求的客户端标识符。
此选项的代码为 61,其最小长度为 2。
网络时间协议服务器选项
此选项指定 IP 地址列表,指示客户端可用的 NTP [18] 服务器。 服务器应该按优先顺序列出。
这个选项的代码是 42,它的最小长度是 4,长度必须是 4 的倍数。
交换机工作原理
三层&二层交换机区别
二层交换机工作原理
当一个数据包到达二层交换机的某个端口时,交换机会首先读取该数据包的源MAC地址和目标MAC地址。然后,交换机会在其MAC地址表中查找目标MAC地址对应的端口。如果找到了对应的端口,交换机就会将数据包转发到该端口。如果没有找到对应的端口,交换机会将数据包广播到所有端口(除了数据包到达的那个端口)。
二层交换功能
- 地址学习(Address Learning)ARL
二层交换机通过地址学习功能来动态学习网络中各个设备的MAC地址。当交换机接收到数据帧时,它会检查帧头中的源MAC地址,并将该地址与接收到帧的端口相关联。这样,交换机逐渐建立了一个MAC地址表,记录了哪个MAC地址连接到了哪个端口。这种动态学习使得交换机能够了解整个网络的设备位置,为后续的帧转发提供便利。
- 帧转发(Frame Forwarding):
帧转发是二层交换机的核心功能之一。当交换机接收到数据帧时,它会检查帧头中的目标MAC地址,并查找与该地址相关联的端口。交换机随后将数据帧仅转发到目标设备所在的端口,而不是广播到整个网络。这种点对点的直接转发方式使得数据传输更加迅速和高效,避免了传统网络中的广播风暴。
- 环路避免(Loop Avoidance):
为了防止网络中的环路,二层交换机使用了环路避免的技术。在一个网络中,当存在多个交换机连接时,如果不谨慎配置,可能会出现数据在网络中无限循环的情况。为了避免这种情况,二层交换机使用诸如STP(Spanning Tree Protocol)等协议来检测并关闭形成环路的冗余链路,保持网络的稳定性。
二层交换机的优点和缺点
- 优点
- 根据唯一的 MAC 地址转发数据包: 二层交换机通过学习和存储设备的 MAC 地址,可以直接根据目标 MAC 地址转发数据包,提高了数据传输的效率。
- 不涉及设置或管理: 部署和维护二层交换机相对简单,不涉及复杂的设置和管理。
- 可以以较低的成本快速部署: 由于功能较为简单,二层交换机的部署成本相对较低。
- 流量核算能力: 二层交换机可以对流量进行基本的核算,提供对网络使用情况的简单监测。
- 低延迟并提高安全性: 由于直接根据 MAC 地址转发数据包,二层交换机通常具有较低的延迟,并提供一定程度的安全性。
- 缺点
- 转发数据包时无法实现任何智能: 二层交换机主要基于 MAC 地址进行操作,无法执行更高层次的智能操作,如路由或过滤基于 IP 地址的流量。
- 无法执行基于 IP 地址的路由或交换: 由于仅关注 MAC 地址,二层交换机无法进行基于 IP 地址的路由,限制了其在复杂网络中的应用。
- 无法保证 VoIP(IP 语音)用户所需的带宽: 对于对带宽要求敏感的应用,如VoIP,二层交换机难以提供对带宽的精确保证。
三层交换机
-
三层交换机能够在网络中进行路由,不仅基于 MAC 地址,还能够识别和处理 IP 地址。这使得它在处理网络层信息时更为灵活。
-
不同于二层交换机仅使用 MAC 地址,三层交换机使用 IP 地址和 MAC 地址来进行数据包的转发和路由决策。
-
与二层交换机相似,三层交换机也能够创建并存储虚拟局域网(VLAN),将大的广播域分割成小的广播域,提高网络的可管理性和性能。
-
通常情况下,三层交换机的数据传输速度比二层交换机更快。这是因为它能够在网络层进行更智能的路由决策,适用于更复杂的网络拓扑。
-
尽管在工作层次上有所不同,三层交换机的地址学习和环路避免功能与二层交换机非常相似。它们仍然需要学习网络中的设备地址,并采取措施防止网络中的环路。
三层交换机工作原理
三层交换机的工作流程与二层交换机类似,但是它在处理数据包时会额外考虑IP地址。当一个数据包到达三层交换机的某个端口时,交换机会首先读取该数据包的源IP地址和目标IP地址。然后,交换机会在其IP路由表中查找目标IP地址对应的端口。如果找到了对应的端口,交换机就会将数据包转发到该端口。如果没有找到对应的端口,交换机会使用路由协议(如RIP、OSPF等)来确定应该将数据包转发到哪个端口。
三层交换机通信过程
-
同一 VLAN 内通信(二层交换机转发):
当两台主机在同一 VLAN 内时,三层交换机就像二层交换机一样,通过查找 MAC 地址表将帧直接转发到目标主机。
-
不同 VLAN 之间通信(三层交换机转发):
当主机需要与另一子网中的设备通信时,帧被发送到默认网关,即三层交换机。 -
三层交换机执行以下步骤:
- 解封装 IP 数据包。
- 与路由表比较,查找匹配的路由。
- 封装数据包并通过匹配路由表的出接口发送。
- 根据目标 MAC 地址确定转发路径。
-
SVI(Switch Virtual Interface):
- SVI 是交换机上的虚拟接口,与特定 VLAN 相关联,允许交换机像其他 IP 设备一样在该 VLAN 中发送和接收 IP 数据包。
- SVI 具有与 VLAN 相关联的 IP 地址。
-
目标 MAC 地址决定转发路径:
- 如果目标 MAC 地址是广播或多播,则帧将从分配给传出 VLAN 的所有物理端口广播出去。
- 如果目标 MAC 地址是单播,则根据 MAC 地址表找到匹配的物理端口进行转发。
VLAN虚拟局域网相关知识点
概念:VLAN是一种将网络划分为多个广播域的技术。在每个广播域中,用户可以彼此自由通信。对于不同VLAN之间的连接,VLAN标记和VLAN间路由是用户必须知道的两个必要术语。
VLAN标记是在帧穿过VLAN中继端口时在帧中添加特殊标记,以允许来自不同VLAN的帧交叉
双标签使用与特点
- 原理
- 外层VLAN主要用于穿越公网使用,此时在公网传送时候,只使用外层的VLAN做为转发依据,内层透明传送,外层VLANTPID使用0x9100/0x9200/0x88a8,内层只能使用0x8100.
- VLANID组合要求
- 内层必需是8100,外层可以为0x9100,88a8;如果为其他值将判断为不合规的双标签。
TLS规范&问题汇总(基于CANOE的开发过程)
概念与关键词
- TLS(传输层安全协议transport layer security)此协议是基于TCP,基于UDP的称为DTLS
- CA:服务器以公钥证书的形式呈现其服务身份的概念,该公钥证书是由证书颁发机构(certification authority,CA)在互联网公钥基础设施的上下文中使用X.509[PKIX]颁发的
- CA的真伪鉴别需要使用签发机构的公钥来进行验证;如果拿到完整的工具链的话,只需知道根证书的公钥CA即可,使用根密钥验证中间CA,而后从中间CA证书中提取其公钥,往下验证即可!
- CA如何确保证书可信任:服务器的证书由中间证书来背书,中间权威机构又会由根证书来背书,这中间的认证链接关系称为信任链(trust chain),而这个最终的颁发根证书机构,称作信任锚点(Trust Anchor)。而操作系统或是浏览器通常会内置很多知名的权威根证书机构的公钥证书,所以通信传输中无需传输根证书机构的证书,这使得最终的信任链如递归一样有一个结束条件,不至于陷入死循环中。本地要预布置根证书公司的公钥证书,而传输过程需要使用完整的证书链,可以去掉RootCA
X509 公钥证书文档结构
协议类型
- 握手协议(type=22)
+ - 警告协议(type=21)&告警类型
- 密码变更协议(type=20)
- 应用数据协议(type=23)
TLS报文结构
记录层+协议层:记录层结构
记录协议(Record Layer)
记录协议根据rfc描述记录协议(Record Layer)有如下4种类型,即上图中Content Type可以取的值。
record layer
记录协议(Record Layer) 数据结构对照着wireshark抓包为:Content Type:Handshake(22), Version: TLS 1.0(0x0301), Length: 512
数据结构:
握手协议(Handshake Protocal)
数据结构:
握手协议中SessionID使用规范
- 如果ClientHello中的SessionID不为0,而是一个特定的32字节的数据,表明本地存在一个TLS数据备份,此时如果SERVER收到此握手信息,并在本地检测到相同的SESSIONID的信息,只需重新开始这个加密密钥即可,省去密码交互过程!
- 不管ClientHello是0还是非0值,如果ServerHELLO中SESSIONID与之不同,即表示启用一个新的握手过程,此时Client应该记录此SessionID;
密钥套件名称格式
Diffie-Hellman 密钥交换
(Diffie-Hellman key exchange)基本原理是:通信双方通过交换一些可以公开的信息就能够生成出共享的秘密数字,而这一秘密数字就可以被用作对称密码的密钥,实际上双方并没有真正交换密钥,而是通过计算生成出了一个相同的共享秘钥。因此,这种方法又称为Diffie-Hellman 密钥协商(Diffie-Hellman key agreement)。
X509证书相关规范与格式解读
https://zhuanlan.zhihu.com/p/686039771
业务流
下面我们以服务器单向认证为例,介绍TLS握手协议的详细流程:
-
Client Hello: 客户端向服务端发送ClientHello消息,消息内容包括:
支持的TLS版本
32字节的随机数(客户端生成,用于生成主密钥master key)
会话ID
加密套件
压缩算法 -
Server Hello: 服务器根据收到的ClientHello消息内容以及本地支持的TLS版本和加密套件确定本次通信的SSL版本和加密套件,并通过ServerHello消息通知给客户端, 消息内容包括:
服务端采纳的本次通讯的TLS版本
32字节的随机数(服务端生成, 用于生成主密钥master key)
会话ID
服务端采纳的用于本次通讯的加密套件, (从ClientHello加密套件中选择一个双方都支持的)
压缩算法 -
Certificate: 服务器将服务端数字证书和证书链通过Certificate消息发送给客户端,客户端基于该消息:
检查服务端数字证书的证书链,验证服务端身份
如果密钥协商算法为rsaKeyAgreement,则使用服务端数字证书中携带的服务端公钥对预备主密钥进行加密。 -
Server Key Exchange: 密钥交换阶段(可选步骤),只有在新建会话并使用ecdh密钥协商时有效,该消息包含服务端密钥协商DH参数,如下:明文传送,可以公开的数据内容,其实加密也没有任何意义,因为验签的时候,证书公钥是公开的,此时加密也会被对方使用公开的公钥解密,相当于明文传送了
-
ecdh密钥协商使用的密码算法
基于密码算法所生成的临时公钥(用于生成主密钥) -
Server Hello Done: 服务器发送ServerHelloDone消息,通知客户端版本和加密套件协商结束
-
Client Key Exchange: 客户端验证服务器证书合法后,将客户端密钥协商部分通过
-
ClientKeyExchange消息发送给服务器, 消息内容包括:
- 如果密钥协商为rsaKeyAgreement, 则为主密钥密文(客户端从服务端发送的Certificate消息中提取服务端公钥,对pre master secret进行加密获得)
- 如果密钥协商为ecdhKeyAgreement, 则为客户端DH参数。
-
该消息发送成功后,客户端和服务端,都得到了完整的主密钥:
- 如果密钥协商为rsaKeyAgreement, 服务端使用自己的私钥解密收到的ClientKeyExchange消息携带的主密钥密文
- 如果密钥协商为ecdhKeyAgreement, 服务端和客户端运行DH算法,根据服务端DH参数和客户端DH参数, 计算得到。
因为证书是非对称的方式进行的,里面含有相关的公钥,Client->Server传送此Pre Master Key的时候,采用此公钥加密,后上传。因为公钥加密只能相应的私钥来完成解密,所以此处加密即可以保证这个过程传递的数据的安全,不会泄露,此时ECDHE所需的密码就可以实现保密
-
-
Change Cipher Spec: 客户端发送ChangeCipherSpec消息,通知服务器后续报文将采用协商好的主密钥和加密套件进行密文通信。
-
Finished: 客户端基于交互过程中收到的服务端握手消息**,计算Hash值,并使用协商好的密钥和加密套件进行加密,通过Finished消息发送给服务器。服务端进行解密和验证。**
* 这些数据涉及哪些内容,怎么打包?? -
Change Cipher Spec: SSL服务器发送ChangeCipherSpec消息,通知客户端后续报文将采用协商好的密钥和加密套件进行密文通信
-
Finished:服务端基于交互过程中收到的客户端握手消息,计算Hash值,并使用协商好的密钥和加密套件进行加密,通过Finished消息发送给客户端。客户端收到后进行解密和验证。协议执行到这里,表明客户端和服务端密钥协商成功。
-
Application Data:客户端和服务端交互使用密文进行通信,保证了通信消息的隐私性
握手协议HELLO过程扩展数据解析
Server_name type=0
用于指定服务器的名字,此服务器的名字需与CA证书中的服务器名保持一致
服务器名来自CA证书内容
- 扩展报文格式
长度为:该属性对应属性内容实际长度,不包含长度字段本身
支持签名算法 TYPE=13
支持签名算法 TYPE=13
支持签名算法 TYPE=13
记录大小限制 TYPE=28
允许设置TLS的记录大小限制扩展。默认值为16384,这也是最大值。
最小值为64。
支持签名算法 TYPE=13
支持签名算法 TYPE=13
支持签名算法 TYPE=13
支持签名算法 TYPE=13
CAPL实现TLS过程
先定义相应的证书链
- Every private key requires a matching certificate. The import of a private key without certificate is not possible.私钥需要与CA证书成对存在,不能脱离CA证书单独使用私钥
- All imported certificates and keys are stored in plain text in the security profile. The files themselves are not contained in the security profile.
- Only X.509 certificates are supported. The following codings are supported:支持的证书类型,或是文件存储类型
- .CER: DER- or Base64-coded certificate
- .CRT: DER- or Base64-coded certificate
- .DER: DER-coded certificate
- .PEM: Base64-coded certificate, enclosed by -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----
- In addition, files with private keys that are DER- or PEM-coded can also be imported.私钥的存储格式或是文件存储类型
- The file name extension is then e.g. .KEY or .PEM.
- With PEM, the Base64-encoded keys must be enclosed with one of the following additions (END accordingly).
- -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----
- -----BEGIN EC PRIVATE KEY----- and -----END EC PRIVATE KEY-----.
- Since PEM clearly defines the beginning and end of a component, you can also write multiple certificates and keys to a single PEM file. With DER this is not possible.
- Password protected keys cannot be imported. PEM, PKCS12 and PKCS8 encrypted containers are supported. The decryption password will be required on import and the key material will be stored (unencrypted) in the Security Manager database.
实操添加相应的CA证书链&PSK预共享KEY
- 添加完整的CA证书链
- 并在服务器所对应的证书,一般为最底层的CA证书添加相应的私钥,如果中间证书或是根证书有私钥也可以添加,方法与添加CA证书方式一样,由工具自动解析为CA或是privateKey
- 可以添加多个证书链组,每个名称需要保持唯一
- 每个证书的名,可以在相应的安全协议中引用,故需保持唯一,其在程序中也可以被引用
NTP协议原理与实现
NTP(Network Time Protocol): 是一种用于网络时间同步的协议。它旨在确保计算机和其他网络设备具有准确的时间,并通过与时间服务器进行通信来同步其时钟。
NTP服务器: 是提供时间服务的特定服务器,它们通过网络向客户端提供准确的时间信息。这些服务器通常与原子钟或其他高精度时间源同步,以确保提供高度准确的时间。
原理
- T1:时间同步请求时间
- T2:时间服务器接收到请求时间
- T3:时间服务器响应时间
- T4: 时间同步请求响应时间
上述几个报文字段有如下关系:先假设应答报文到达本地的时间为T4,则,
报文往返时延Delay=(T4-T1)-(T3-T2)
客户端与时钟源的时间差offset=((T2-T1)+(T3-T4))/ 2
注:
- 假设网络延时为一个固定值,往返均为固定值
UTC与NTP时间戳之间转换
UTC是从1970年1月1号开始算的,NTP的时候戳是从1900年1月1号开始算的,所以生成的UTC值需要加差70年
①NTP时间戳用一个64bit无符号定点数表示,它表示自从1900年1月1日00:00:00到现在过了多少秒。64bit分为两部分,高32bit(MSW)表示整数部分,单位是秒;低32bit(LSW)表示小数部分,单位是232皮秒。
②UTC时间,格林威治时间1970年1月1日00:00:00(北京时间1970年1月1日08:00:00)起至现在的总秒数,表示为1970-01-01 00:00:00 UTC。程序里习惯叫做UTC时间戳。
NTP协议中有四个时间戳,本文不讨论这四个时间戳的区别,只简单的拿其中一个NTP时间戳报文分析如何转换成UTC时间。例如一段时间戳报文为“D9 FD 84 95 94 F8 59 7C”,下面我们一起学习该NTP时间戳是如何转换成UTC时间的。
先处理MSW高位32bit“D9 FD 84 95”,将其转换为10进制3657270421,由于NTP时间和UTC时间起始不同,需要将该时间减少70年(1900年到1970年)2208988800(0x83AA7E80),则为1448281621,使用UTC转换器为2015-11-23 12:27:01 UTC(格林威治时间),2015-11-23 20:27:01 UTC+8(北京时间 UTC+8)
然后再处理LSW低位32bit“94 F8 59 7C”,在处理LSW之前先要了解1LSW=232ps是怎么来的,1 second =1,000,000,000,000 picoseconds,这个值很大,而2^32=4294967296,很明显用32bit无法精确到1 picoseconds,那就尽力而为,于是自然就把1,000,000,000,000 picoseconds劈成2^32份:
1,000,000,000,000/(2^32) = 232.83064365386962890625 即1LSW=232ps
故先将LSW乘以232转为ps,然后ps除以10^6就得到us了,于是有:usec=lsw*232/1000000
再看看秒的一些时间单位转换:
毫秒ms是10-3秒;微妙us是10-6秒;纳秒ns是10-9秒;皮秒ps是10-12秒
于是低位32bit“94 F8 59 7C”,将其转换为10进制2499303804,则:
usec=lsw*232/1000000=579838us=0.579838s
综上所述,故NTP时间戳“D9 FD 84 95 94 F8 59 7C”转换成UTC时间为2015-11-23 20:27:01.579838 UTC+8(北京时间)
协议动议指导文档:https://www.cnblogs.com/ColoFly/p/12343614.html
详细的流程指导:https://blog.csdn.net/yekui006/article/details/121371385?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-121371385-blog-86620396.235v43control&spm=1001.2101.3001.4242.1&utm_relevant_index=3
==================================================
项目脚本设计前知识梳理随手记,没有系统整理,也可能存在错误信息,请甄别使用。如果你好的思路也可以分享,共同学习,后期项目完成后有空再系统整理!
https://blog.csdn.net/usstmiracle/article/details/130968142
SOMEIP协议规范与测试规范
SD报文包的基本结构
-
SOME/IP为SD与非SD类的消息共享部分
-
SOMEIP SD部分为SD专享部分内容,METHOD,EVENT,FIELD等具体消息结构无此部分,而是对应的负载数据1 概述
服务发现模块的主要任务是管理在车内通信中被称为服务的功能实体的可用性,以及控制事件消息的发送行为。只允许向需要这些事件消息的接收器发送事件消息(发布/订阅)。这里描述的解决方案也被称为SOME/IP-SD(基于IP -服务发现的可扩展的面向服务的MiddlewarE)。通过使用服务发现,不同的ECUs可以提供服务实例,并在车辆网络中找到可用的服务实例。ECU可以停止提供它以前提供的服务实例。稍后找到这样的服务实例将保持未应答。服务实例是由其服务接口定义的服务的单一实现。
报文格式
SOME/IP-SD消息格式
Message ID:固定为0xFFFF8100
Client-ID:设置为0x0000,因为只存在一个SOME/IP-SD实例
Session-ID:并根据某些/IP要求处理它,每发出一个SOME/IP-SD报文,Session-ID加1,只能从 1 开始,不能设置为0。SOME/IP-SD会话ID处理是根据“通信关系”完成的,即组播和单播是对等的
Protocol Version :固定为0x01,
Interface Version :固定为0x01,
Message Type :固定为0x02,
Return Code :固定为0x00
**
**
SOME/IP-SD 头部
Flags: 使用Flags字段,将启动SOME/IP-SD标头。它用于信号显示全局服务发现信息,其中包括当前上次重新启动的状态以及接收单播消息的能力。
**该字段第0位表示"Reboot Flag"。SOME/IP-SD首部的重启标志应该设置为1,直到SOME/IP首部中的Session-ID绕回0(wraps around),重新从1开始。**
Entries Array
当SOME/IP-SD找到或提供服务实例或处理订阅时,这将通过所谓的条目来完成,这些条目将在SOME/IP-SD消息的条目数组中传输。
协议中有两种条目:一种服务条目,另一种事件组条目。
服务条目
服务条目有16个字节大小,包含的字段如下所示:
- 类型字段[uint8]:FindService (0x00), OfferService (0x01) and StopOfferService (0x01)
- 第一个选项运行索引[uint8]:代表选项排列中第一个选项索引位置
- 第二个选项运行索引[uint8]:代表选项排列中第二个选项索引位置
- 选项1的数量[uint4]:描述第一个选项运行使用的选项数量
- 选项2的数量[uint4]: 描述第二个选项运行使用的选项数量
- Service-ID[uint16]: 描述此条目所关注的服务或服务实例的服务ID。
- Instance ID[uint16]: 描述此条目所涉及的服务实例的服务实例ID,如果表示一个服务的所有服务实例,则设置为0xFFFF
- Major Version[uint8]: 服务(实例)的主版本
- TTL[uint24]: 描述条目的生命周期,单位为秒
- Minor Version[uint32]: 服务的次版本
事件条目
- 类型字段[uint8]:Subscribe (0x06), StopSubscribeEventgroup (0x06),
- SubscribeAck (0x07) and SubscribeEventgroupNack (0x07).
- 第一个选项运行索引[uint8]:代表选项排列中第一个选项索引位置
- 第二个选项运行索引[uint8]:代表选项排列中第二个选项索引位置
- 选项1的数量[uint4]:描述第一个选项运行使用的选项数量。0表示没有选项
- 选项2的数量[uint4]: 描述第二个选项运行使用的选项数量。0表示没有选项
- Service-ID[uint16]: 描述此条目所关注的服务或服务实例的服务ID。
- Instance ID[uint16]: 描述此条目所涉及的服务实例的服务实例ID,如果表示一个服务的所有服务实例,则设置为0xFFFF
- Major Version[uint8]: 编码这个eventgroup所属的服务实例的主版本。
- TTL[uint24]: 描述条目的生命周期,以秒为单位
- 保留字段[uint12]: 设置成0x000
- Counter[uint4]: 用于区分同一订阅服务器的相同订阅事件组。如果不使用,设置为0x0。
- Evntgroup ID[uint16]: 传输事件组的ID
Options Array
选项数组是服务发现消息的最后一部分。选项数组中的选项包含附加信息。
IPv4 Endpoint Option
IPv4端口Option的格式如下:
- Length字段,2个byte,应设置为0x0009
- Type字段,1个byte,应设置为0x04
- Discardable Flag,1个bit,应设置为0
- Bit1到Bit7是保留位,全部为0
- IPv4-Address字段,4个byte,服务实例所在的主机的IPv4地址
- Reserved,1个byte,设置为0x00
- Transport Protocol字段,1个byte,传输层协议,0x06是TCP,0x11是UDP
- Transport Protocol Port Number,2个byte,传输层端口
IPv6 Endpoint Option
IPv6端口Option的格式如下:
- Length字段,2个byte,应设置为0x0015
- Type字段,1个byte,应设置为0x06
- Discardable Flag,1个bit,应设置为0
- Bit1到Bit7是保留位,全部为0
- IPv6-Address,16个byte,服务实例所在的主机的IPv6地址
- Reserved,1个byte,设置为0x00
- Transport Protocol,1个byte,传输层协议,0x06是TCP,0x11是UDP
- Transport Protocol Port Number,2个byte,传输层端口
SD服务发现行为
SD通信主要涉及到3类报文:Find Service、Offer Service和Subscribe报文。
服务端和客户端的通信行为包含以下几个阶段:
Server Services
Down Phase
在这个阶段,Service是不可用的,即服务端无法提供服务。
Initial Wait Phase
当服务准备完毕(Available)后,进入此阶段;
如果此阶段收到Find Service报文,服务端忽略此消息,不做任何处理;
如果服务不可用了,将返回进入Down Phase;
此阶段需要定义时间参数INITIAL_DELAY_Min和INITIAL_DELAY_Max,初始化时间取其之间的随机值,当定时器超时后,发送第一帧Offer Service,标志着进入下一个阶段。
Repetition Phase
为了让客户端快速找到有哪些Service,此阶段重复发送Offer Service,重复次数由REPETITIONS_MAX决定;
发送间隔以REPETITIONS_BASE_DELAY为基本时间,每发送一次,间隔是前一间隔的2倍;
如果收到某客户端的Find Service,不影响当前阶段的发送计数和计时,延迟一定时间(REQUEST_RESPONSE_DELAY)后,单独发送单播Offer Service给服务请求端;
如果收到SubscribeEventgroup后,发送单播Ack/Nack,启动此订阅Entry的TTL计时器;
如果收到StopSubscribeEventgroup后,停止此订阅Entry的TTL计时器;
如果服务不可用,离开此阶段进入Down Phase,并发送StopOfferService通知所有客户端。
Main Phase
此阶段将周期性发送Offer Service,周期时间为CYCLIC_OFFER_DELAY;
如果收到某客户端的Find Service,不影响发送计数,延迟一定时间(REQUEST_RESPONSE_DELAY)后,发送单播Offer Service给服务请求端;
如果收到SubscribeEventgroup后,发送单播Ack/Nack,启动此订阅Entry的TTL计时器;
收到StopSubscribeEventgroup后,停止此订阅Entry的TTL计时器;
如果服务不可用,离开此阶段进入Down Phase,并发送StopOfferService
Client Services
Down Phase
服务未被应用请求;
收到Offer Service,存储当前服务实例状态,启动TTL计时,此时服务若被应用请求,直接进入Main Phase。
Initial Wait Phase
服务被请求后,进入此阶段;
等待INITIAL_DELAY时间(最大和最小值之间的随机值);
如果此时收到Offer Service,则取消计时器,直接进入Main Phase;
如果服务请求被释放,进入Down Phase;
计时器超时后,发送第一个Find Service,进入下一阶段。
Repetition Phase
重复发送Find service,重复次数由REPETITIONS_MAX决定;
发送间隔以REPETITIONS_BASE_DELAY为基时间,每发送一次间隔加倍;
收到Offer Service,停止发送计数和计时,立即进入Main Phase;触发发送SubscribeEventgroup(延迟一定时间);
如果服务请求被释放,进入Down Phase;若有订阅,则发送StopSubscribeEventgroup。
Main Phase
不再周期发送Find Service;
收到Offer Service,触发发送SubscribeEventgroup(延迟一定时间);
如果收到StopOfferService,则停止所有计时器;
如果服务请求被释放,进入Down Phase;若有订阅,则发送StopSubscribeEventgro
通信服务逻辑
为什么收到OFFER后Client会发先发送Stop Subscribute
因为Subscribute TTL的时间大于OFFER的周期时间,如果在收到OFFER的时候,此订阅还没有到期就要先发送一条STOP SUBSCRIBUTE先停止上次的订阅服务,而后再重新订阅!
订阅TTL远大于OFFER的TTL,且OFFER周期发送
如OFFER TTL=3 周期2秒循环发送,那第么此时如果订阅此服务的TTL=300,实际情况是在这个订阅有效期内,后续如果不再订阅,理论上从上次订阅300秒内都是有效的。
每次发送一个OFFER,其SERVER均为重新初始化服务的计时器,所以该服务在SERVER端是一直有效;
CLIENT端每收一条OFFER也会更新该OFFER的状态,并重置该服务的TTL,表明该服务还是UP状态,
SD中Reboot控制逻辑
SD服务因为使用相同的PORT即默认为30490,SERVER端会维护一个组播SESSIONID,并为每个不同IP或是ECU设置一个相应的单播SESSIONID值,目前理解:只要所维护的SESSIONID计算到FFFF再返回1的时候,即RebootFlag就变0.Client与Server端使用的相同的策略,Client组播只用于FIND,单播用于订阅,通过单播与组播的RebootFlag&SessionID值判断ECU是否重启
EVENT与Filed区别
Event仅在发生某些事情时发生,事件没有初始值,未定义事件的生命周期。基于状态的元素应建模为字段,Event 和 Field 的事件消息是相同的,区别在于初始事件仅存在于字段。通常将事件用于时间有限的观察,将字段用于状态等数据。所以首次订阅FIELD的时候,立即返回一个初始值,而EVENT不用返回初始值
错误处理逻辑
哪些情况会响应错误报文
- SD服务的时候:
- 服务查找与服务发布:如果为多播地址的时候,出现错误将直接丢弃,不做任何处理;即便是单播FIND或OFFER,如果出现异常,也只做丢弃处理,不做任何响应
- 订阅与订阅响应:当前出现字段数据异常时候,只以NACK来响应,不通过错误帧回应对方
- RPC与订阅消息发送报文:此时均是以单播形式发送的报文,此时收到订阅消息通知或是Request/Response检测出任何错误,均以错误消息形式提示对方【订阅不遵循错误处理逻辑,要么订阅成功,要么订阅失败,无法识别时候丢弃】
错误处理方式与逻辑
- 错误消息结构:复制源数据的MessageID(告诉对方哪个消息请求错误),RequestID(定位错误的标签,即哪次消息是错的)
订阅后未收到ACK,后续逻辑处理
订阅后如果没有收到ACK或是NACK,表明此Client未能知识订阅的结果,此时如果再收到OFFER的时候,在再次订阅前应该先发送STOP,而后再次订阅!
SD特定字段的含义
SD之服务发现与提供Entry结构体
InstanceID的使用规则
- 在SERVER端该值只能提供指定的服务实例编号,在Client请求时候如下值为指定非0xFFFF值时,表示查询或是订阅该服务下全部服务实例
Major Version&Minor Version的使用规则
1.如果两者值均不为全FF特定值的时候,表示请求特定的版本的服务;(注:在实际服务定义可能出现SERVICEID相同,INSTANCEID相同,只是不同的版本的情况,所以可通过此值的组合实现服务的代差的区分)
2.如果任一值为全FF的时候,表示请求所有SERVERID与INSTANCEID相同的服务,不必区分版本信息,全部返回!!即SERVER收到这类FIND SERVER Discovery服务的时候,不检测版本信息
SD Entry中的TTL作用
TTL实际只在Offer Service Discovery中有计时意义,当TTL计时结束后,表明该服务失效,该服务提供的所有METHOD,EVENT,FIELD均失效,EVENT不再提供服务软件,RPC请求将不会响应
但对于如Find Sevice Discovery与SubscribeEventGroup与SubscribeEventGroupACK结构中的TTL无计时作用,用于订阅时候,TTL=0表示停止订阅,TTL=非0 表示订阅 订阅响应时候,如果TTL=0表明订阅失败NACK TTL=非0表明订阅成功即ACK
SESSIONID使用规则
SOME/IP(Scalable service-Oriented Middleware over IP)是一种在车载以太网通信中广泛使用的协议,它支持单播和组播两种传输方式。在SOME/IP中,SessionID(会话ID)是用于标识和管理通信会话的重要元素。在单播与组播的使用上,SOME/IP的SessionID存在以下区别:
1. SessionID的生成与分配
**单播:**在单播通信中,SessionID是针对每一个独立的通信会话生成的。**当一个客户端(Client)向服务端(Server)发起请求时,会建立一个独立的会话,并分配一个唯一的SessionID来标识这个会话。**这个SessionID在后续的通信过程中用于区分不同的会话和数据流。
**组播:**在组播通信中,虽然数据是同时发送给多个接收者,但并不意味着每个接收者都会收到一个独立的SessionID。组播的本质在于其“一对多”的通信模式,即一份数据报文通过组播地址发送给一组接收者,而不是为每个接收者单独建立会话。因此,在组播通信中,SessionID的分配和使用可能与单播有所不同,具体取决于SOME/IP协议的实现和应用场景。
2. SessionID的管理与同步
**单播:**在单播通信中,SessionID的管理相对简单,因为每个会话都是独立的。服务端和客户端可以通过SessionID来同步和管理会话状态,如会话的建立、数据的传输和会话的终止等。
**组播:**对于组播通信,由于数据是同时发送给多个接收者,因此可能需要一种机制来确保所有接收者都能正确地接收和处理数据。虽然组播通信本身不直接为每个接收者分配独立的SessionID,但SOME/IP协议可能通过其他机制(如组管理协议、多播地址等)来确保数据的正确传输和接收。
3. SessionID的注意事项
在SOME/IP协议中,无论是单播还是组播通信,都需要确保SessionID的唯一性和正确性。这有助于避免会话冲突和数据错乱等问题。
对于组播通信,虽然不直接为每个接收者分配独立的SessionID,但协议实现时可能需要考虑如何确保数据的可靠传输和接收者的正确识别。
SD Option配置要求
CAPL 的SOMEIP IL针对订阅响应时候,若事件组没有提供组播IP信息时候,会报异常,此时可以使用如下方式进行处理
下述代码向指定事件组添加组播ENDPOINT信息,但是同时将MulticastThreshold属性设置为0,即表示不管当前服务被多少消费端订阅均使用单播形式发送,不使用组播!
peg_0203=SomeIpAddProvidedEventGroup(psi_0203,1);
SomeIpSetProperty(peg_0203,"MulticastIp",ipGetAddressAsNumber("239.192.255.251"));
SomeIpSetProperty(peg_0203,"MulticastPort",30501);
SomeIpSetProperty(peg_0203,"MulticastThreshold",0);
SESSIONID的使用依据
每个终端均维护一个组播SESSIONID与单播SESSIONID,PSI端所有服务事件组的订阅响应ACK&NACK共用此单播SESSIONID,OFFERSERVICE共享组播SESSIONID,响应FIND SD服务的,单播OFFER SD也使用单播SESSIONID
CSI服务消费端的也共享一组组播与单播SESSIONID值,所有单播请求如METHOD,服务事件组的订阅服务使用单播SESSIONID
单播与组播由于计数独立,而SOMEIP协议包的FLAG字段的REBOOT位与此SESSIONID强相关:当组播的SESSIOID计到0xFFFF重新计数的时候,此时组播报文中的REBOOT位将设置为0,当单播SESSIONID计到0xFFFF后,再次从1计数的时候,此时单播的REBOOT位置0.两者单独维护,不共享!
数据序列化处理
字符串序列化处理
字符串一般采用【长度】+【BOM]】+数据内容+【\0】
CAPL SOMEIP FUNCTION
long SomeIpSetData( dword messageHandle, dword dataLength, char data[] )
只有设置SOMEIP报文的数据长度后,报文才是有效报文,即使发送长度为0,也要调用此接口函数对SOMEIP的报文进行长度赋值,否则报文无法在SOMEIP-IL中发送出去
//在服务提供端,可以直接操作FILED类型的变量,对其附载进行赋值操作
serviceHandle = SomeIpCreateProvidedServiceInstance(appEndpointHandle, 258 /*serviceId*/, 1 /*instanceId*/);
pf_filed=SomeIpAddField(serviceHandle,0x8009,0x3396,0x2562);//此函数返回的messagehandle类型的变量
SomeIpAddFieldToEventGroup(providedEventgroupHandle,pf_filed);
SomeIpSetData(pf_filed,200,buffer);//设置相应的参数
SomeIpCommitField(pf_filed);//触发相应的发送时间
//如果在服务消费端的时候,事件与FIELD都是接收,而METHOD是发起的请求,故只有METHOD可以通过SomeIpSetData进行负载的配置操作
// create Service Instance
csi = SomeIpCreateConsumedServiceInstance(aep,257,1);
ret=SomeIpSetProperty("SDMulticastIp",ipGetAddressAsNumber("224.0.0.255"));
ret=SomeIpSetProperty("ClientId",0x54);
ret=SomeIpSetProperty("SDMulticastPort",30490);
// create Eventgroup
ceg = SomeIpAddConsumedEventGroup(csi,1);
// create Event Consumer
cev = SomeIpCreateEventConsumer(csi,0x9001,"CallbackEvent1");
method=SomeIpCreateMethodCall(csi,0x5236,"OnMethodResponse");//返回具有messagehandle属性的句柄,可以使用SomeipSetData直接对其进行负载赋值操作
SomeIpCreateFieldConsumer(csi,0x8009,0x3396,0x2562,"OnSomeIpFieldNotification");
#if 1
SomeIpSetData(method,200,buf);
ret=SomeIpSetData(method,100,buf);//对Method赋值
SomeIpCallMethod(method);//触发Method请求发送
#endif
void OnSomeIpMessage(dword messageHandle)
用于对所有接收到的SOMEIP报文,如果当前SOMEIP有相应的回调处理程序,首先调用相应的回调处理程序,而后再调用OnSomeIpMessage,而如果没有相应的回调处理程序,则会直接调用此处理接口
//事件请求的响应回调函数
void OnMethodResponse(dword methodCallHandle, dword messageResponseHandle)
{
DWORD res; // value of return parameter
// get the returned parameter values
res = SomeIpGetValueDWord(messageResponseHandle,"Result");
write("The method call returned value: %d",res);
writeEx(-3,1,"SomeIpGetMessageId(messageHandle))--comsumer");
}
//通用的报文处理接口
void OnSomeIpMessage( dword messageHandle )
{
writeEx(-3,1,"OnSomeIpMessage--%x",SomeIpGetMessageId(messageHandle));
}
当接收到METHOD报文后,首先调用相应的回调处理程序,而后调用通用OnSomeIpMessage处理程序接口,结果如下
SomeIpILControlInit:只能在on prestart事件中执行此接口,在启动前就要完成初始化,如果执行IL默认处理于STOP状态
SomeIpILControlResume:对SomeIpILControlWait接口处理程序处理后的状态的恢复,恢复EVENT与FILED的正常响应机制
SomeIpILControlStart:启动IL的工作机制,如果是在SomeIpILControlStop执行后再次执行START,需要先重新建立相应的AEP,PSI,CSI等资源,在START前要完成资源的构建。
SomeIpILControlStop:停止IL的工作,停止后相关的资源将全部被清楚,所以如果再次START时候,需要重新建议相关资料,故不建议使用STOP执行IL的关闭操作
SomeIpILControlWait:将停止FILED与EVENT事件的发出,但是SD服务正常响应!
SomeIpSDDesubscribeEventGroup
Informs the Remote-SD that Event Group is no longer needed.此时服务消费端在收到OfferService后不会再发送订阅SD**消费端**
SomeIpSDReleaseService
Informs the local SD that the Remote Service is no longer needed.消费端不再需要CSI服务,此时发送此指令,
服务提供端将停止相应的EVENT,FILED数据的响应;服务在节点(使用者)上未注册。关联的服务发现消息(查找
服务)将不再由节点发送。服务实例和所有分配的事件组、事件、字段和方法在服务实例注销时不会被删除
SomeIpSDRequireService
Informs the local SD that the Remote Service is needed.A service that was unregistered at the node (consumer)
using the SomeIpSDReleaseService function can be registered again with this function.
The associated Service Discovery message (Find Service) is then sent if necessary.
使用SomeIpSDReleaseService函数在节点(消费者)上未注册的服务可以使用此函数再次注册。如果需要,然后发送相关的服务发现消息(查找服务)。
注:
如果服务提供没有周期性发出OFFERSERVICE SD服务的情况下,此时执行此函数,消费端会主动发出FINDSERVICE SD服务!但是如果接收到相应的OFFER SD则停发相应的FIND服务。
SomeIpSDSetServiceStatus(long SomeIpSDSetServiceStatus( dword psiHandle, long up );)
服务的供应端:Informs the Service Discovery of the current status of a provided Service Instance.
的说法:
1: The status is changed to up. The sending of OfferServices is started.
0: The status is changed to own. A StopOfferService message is sent if the service was previously in up status.
如果offerservice正常发送状态,下发状态无DOWN后,此时将发送StopOfferSevice服务
如果当前为STOP状态,设置目标状态为UP时候,将重新发送OFFERSERVICE服务
SomeIpSDSubscribeEventGroup
Sends a Subscribe message.恢复服务消费端在收到offerService后,发送订阅服务。
/**/
long SomeIpSetProperty( char propertyName[], int64 value); // form 1
long SomeIpSetProperty( dword objHandle, char propertyName[], int64 value); // form 2
long SomeIpSetProperty( dword objHandle, char propertyName[], char value); // form 3
long SomeIpSetProperty( char propertyName[], byte buffer[]); // form 4
对SOMEIP IL或相应的OBJECT HANDLE进行相关的属性配置,部分配置是基于总线的上下文
函数FORM1 long SomeIpSetProperty( char propertyName[], int64 value) 实现如下配置
1. ClientId:SomeIP-ClientId. Included in every message 与SessionID共同组成RequestID加入到每条SOMEIP报文中
2. MaxUDPMessageLength:Sets the maximum allowed size of a SOME/IP message. Maximum size: 65519 用于传输协议的配置,设置UDP一次最大一次传送的报文数量,即分段后的总的数量
3. SDMulticastIp:If SD is done per IPv4, SD sends multicasts to this IPv4 destination address SD服务所用的组播IP地址
4. SDMulticastPort:SD sends multicasts to this port and, if necessary, opens a local endpoint with this port SD服务组播UDP所用的PORT值
5. SDMulticastIPv6:IPV6 组播所有的地址
6. VlanId:This property may be set in on preStart to select a VLAN which needs to be configured for the current bus
context. Furthermore the IL will use the first IP address of this VLAN for ServiceDiscovery and application endpoints
that are created by SomeIpOpenLocalApplicationEndpoint.指定使用的ADAPTER的VLAN的值,通过此VLAN可以指定默
认通信ADAPTER,后续的设置AEP的时候,如果不指定具体IP的地址,将使用包含此VLAN的ADAPTER的第一个IP地址
函数FORM4 long SomeIpSetProperty( char propertyName[], byte value[]) 实现如下配置
待补充
long SomeIpSetProperty( char propertyName[], dword bufferLength, byte buffer[]); // form 5*
对SOMEIP数据包数据内容的处理API
messageHandle报文中包含的信息:
1.包含SOMEIP完整的HEADER,与负载数据内容
2.包含上层UDP或是TCP交互的数据信息(远端IPADDRESS,IPPORT,本地端的IPADDRRESS,PORT等)
//创建并发送一条SOMEIP报文
on key 'c'
{
dword messageHandle;
long ret;
messageHandle=SomeIpCreateMessage(0xFFFF8100,0x540001,0x01,0x01,0x02,0x00);
//创建SOMEIP的报文头部信息,对于SD服务可以通过如下的指定的API进行配置操作
ret=SomeIpSetValueDWord(messageHandle,"Entry",1);
/*
通过此参数配置Entry的数量,且所有参数都默认配置为0,所以如果后续实际配置量:
1.小于此定义量的时候,没有配置的Entry内部的数据内容将全为0
2.大于此定义量的时候,将会按实际配置量生成相应数据量的Entry,且没有详细配置的Entry组将使用默认的参数
*/
ret=SomeIpSetValueDWord(messageHandle,"Entry[0]",0);
/*
通过此操作,配置指定的Entry提供的服务接口的类型,但是如果后期实际的配置的类型与此定义不同的时候,将会转换实际的配置内容
此例:
初始配置Entry[0]=FindService 服务接口
但是后续配置属性字段的时候,将Entry[0]按OfferService来进行匹配,此时Entry[0]即会转换OfferService类型进行输出
同时上述两步可以不必输入,可通过直接属性字段的配置来实际自动添加Entry项
*/
// ret=SomeIpSetValueDWord(messageHandle,"Entry[1]",1);
// ret=SomeIpSetValueDWord(messageHandle,"Entry[2]",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[0].OfferService.ServiceID",0x0203);
ret=SomeIpSetValueDWord(messageHandle,"Entry[0].OfferService.InstanceID",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[0].OfferService.TTL",3);
ret=SomeIpSetValueDWord(messageHandle,"Entry[0].OfferService.MinorVersion",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[0].OfferService.Index1stOptions",0);
ret=SomeIpSetValueDWord(messageHandle,"Entry[0].OfferService.Index2ndOptions",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[1].OfferService.ServiceID",0x0203);
ret=SomeIpSetValueDWord(messageHandle,"Entry[1].OfferService.InstanceID",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[1].OfferService.TTL",3);
ret=SomeIpSetValueDWord(messageHandle,"Entry[1].OfferService.MinorVersion",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[1].OfferService.NumberOfOptions1",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[1].OfferService.NumberOfOptions2",1);
/*
Entry[3]:因为中间缺失索引2,实际会以默认值全0自动加入。Entry与Option的下标均从0开始计算,配置缺失的项,将自动填充
Option 部分内容以Configuration格式来填充,并初始长度为1
Entry:以全0值进行填充,生成相应的点位信息
*/
ret=SomeIpSetValueDWord(messageHandle,"Entry[3].OfferService.ServiceID",0x0203);
ret=SomeIpSetValueDWord(messageHandle,"Entry[3].OfferService.InstanceID",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[3].OfferService.TTL",3);
ret=SomeIpSetValueDWord(messageHandle,"Entry[3].OfferService.MinorVersion",1);
ret=SomeIpSetValueDWord(messageHandle,"Entry[3].OfferService.Index1stOptions",0);
ret=SomeIpSetValueDWord(messageHandle,"Entry[3].OfferService.Index2ndOptions",0);
ret=SomeIpSetValueString(messageHandle,"Option[0].Configuration.String[3]","def-130");
ret=SomeIpSetValueString(messageHandle,"Option[0].Configuration.String[2]","def-129");
ret=SomeIpSetValueString(messageHandle,"Option[0].Configuration.String[1]","def-128");
ret=SomeIpSetValueString(messageHandle,"Option[0].Configuration.String[0]","def-127");
/*
如果是同一个Configuration配置,即Option[n]中的n为同一值时候,String属性值的下标即表示此配置选项有多个Configuration内容,但是实际输出的时候会将其合并为一个Configuration选项,不同内容间用.符号进行连接
同时
*/
SomeIpSetValueDWord(messageHandle, "Option[1].IPv4Endpoint.PortNumber", 30490);
SomeIpSetValueDWord(messageHandle, "Option[1].IPv4Endpoint.IPv4Address", swapDWord(ipGetAddressAsNumber("192.168.21.36")));
/*
OPTION涉及到非字节的数据,就要涉及到存储方式的配置,因为网络传送是大端传送,SomeIpSetValueDWord配置IP地址的时候,未进行大小端转换,所以要手动进行转换
*/
SomeIpSetValueDWord(messageHandle, "Option[3].IPv4Multicast.PortNumber", 30490);
SomeIpSetValueDWord(messageHandle, "Option[3].IPv4Multicast.IPv4Address", swapDWord(ipGetAddressAsNumber("239.0.0.36")));
/*
Option[N]如果此处的N取值不连续的时候,系统会自动用configuration配置项进行填充,其数据长度为1,即只有'\0'结尾字符
*/
SomeIpSetValueDWord(messageHandle, "Option[3].IPv4Endpoint.L4Proto", 17);
ret=SomeIpOutputMessage(aep,ip_Endpoint(UDP:192.168.1.4:50003),messageHandle);
writeEx(-3,1,"ret=SomeIpOutputMessage(aep,ip_Endpoint(UDP:192.168.1.4:50003),messageHandle)=%d",ret);
}
if(SomeIpGetMessageId(messageHandle)==0xFFFF8100)
{
//获取UDP或是TCP相关的配置信息,即通信网络层的相关数据信息的获取
ip.IPV4Address=SomeIpGetDestinationAddress(messageHandle);
ip.PrintAddressToString(msg);
writeEx(-3,1,"TCP/UDP = %d SomeIpGetDestinationAddress--%s Port=%d",SomeIpGetProtocol(messageHandle),msg,SomeIpGetDestinationPort(messageHandle));
ip.IPV4Address=SomeIpGetSourceAddress(messageHandle);
ip.PrintAddressToString(msg);
writeEx(-3,1,"SomeIpGetSourceAddress--%s Port=%d",msg,SomeIpGetSourcePort(messageHandle));
//SOMEIP协议层的数据的获取--包头的数据获取
writeEx(-3,1,"SomeIpGetMessageId--%x",SomeIpGetMessageId(messageHandle));//获取MESSAGEID信息
writeEx(-3,1,"SomeIpGetRequestId--%x",SomeIpGetRequestId(messageHandle));//获取RequestID信息
writeEx(-3,1,"SomeIpGetLength--%d",SomeIpGetLength(messageHandle));//获取包头的长度字段数值信息
writeEx(-3,1,"SomeIpGetProtocolVersion--%d",SomeIpGetProtocolVersion(messageHandle));//获取包头部的协议的版本信息This function returns the Protocol Version from the SOME/IP message header
writeEx(-3,1,"SomeIpGetInterfaceVersion--%d",SomeIpGetInterfaceVersion(messageHandle));//
writeEx(-3,1,"SomeIpGetMessageType--%d",SomeIpGetMessageType(messageHandle));//
writeEx(-3,1,"SomeIpGetReturnCode--%d",SomeIpGetReturnCode(messageHandle));//
}
writeEx(-3,1,"OnSomeIpMessage--%x",SomeIpGetMessageId(messageHandle));
}
PSI添加FIELD与EVENT的处理逻辑
SomeIpAddFieldToEventGroup(peg_0201,Field_9001);
因为FIELD相较于EVENT,区别在于FIELD在订阅成功后,回复完ACK后,立即就要响应并发送一条FIELD通知事件,所以在此之前要对FIELD数据负载进行序列化,否则可能会造成IL报 FIELD序列异常的错误信息
on start
{
long ret;
char msg[200];
ret=ipRouteAddHost(ipGetAddressAsNumber(TGW),macid[0]);
if(ret)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
ret=ipRouteAddHost(ipGetAddressAsNumber(CDC),macid[1]);
if(ret)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
ret=ipRouteAddHost(ipGetAddressAsNumber(BDCU),macid[2]);
if(ret)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
ret=ipRouteAddHost(ipGetAddressAsNumber(V3NK),macid[3]);
if(ret)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
ret=SomeIpSetProperty("SDMulticastIp",ipGetAddressAsNumber("224.0.0.255"));
if(ret)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
ret=SomeIpSetProperty("SDMulticastPort",30490);
if(ret)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
aep_30501=SomeIpOpenLocalApplicationEndpoint(0x11,30501);
aep_30502=SomeIpOpenLocalApplicationEndpoint(0x11,30502);
aep_30503=SomeIpOpenLocalApplicationEndpoint(0x11,30503);
aep_30504=SomeIpOpenLocalApplicationEndpoint(0x11,30504);
if(0==aep_30502||0==aep_30503||0==aep_30504)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
psi_0201=SomeIpCreateProvidedServiceInstance(aep_30502,0x0201,1);
if(0==psi_0201)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
psi_0202=SomeIpCreateProvidedServiceInstance(aep_30503,0x0202,1);
if(0==psi_0202)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
psi_0203=SomeIpCreateProvidedServiceInstance(aep_30504,0x0203,1);
if(0==psi_0203)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
csi_0301=SomeIpCreateConsumedServiceInstance(aep_30501,0x0301,1);
if(0==csi_0301)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
ceg=SomeIpAddConsumedEventGroup(csi_0301,1);
cev_8001=SomeIpCreateEventConsumer(csi_0301,0x8001,"CallbackEventTotalMileage");
cev_8002=SomeIpCreateEventConsumer(csi_0301,0x8002,"CallbackEventSpeed");
//Add Event To PSI
Method_0001=SomeIpAddMethod(psi_0201,0x0001,"OnMethod_CallOperation");
if(0==Method_0001)
{
SomeIpGetLastErrorText(elcount(msg),msg);
WriteLog(msg);
}
peg_0201=SomeIpAddProvidedEventGroup(psi_0201,1);
SomeIpSetProperty(peg_0201,"MulticastIp",ipGetAddressAsNumber("239.192.255.251"));
SomeIpSetProperty(peg_0201,"MulticastPort",30501);
SomeIpSetProperty(peg_0201,"MulticastThreshold",0);
/*
按正常逻辑订阅响应ACK的时候,MultiCast Endpoint可以是0-1个,但是IL如果没有对事件组提供组播地址的时候,会有警报信息,为了消除这个警报信息,特加入此信息
同时将MulticastThreshold设置为0,这样即表示为全程不管接入多少NODE,均以单播形式传送数据
*/
Event_8001=SomeIpAddEvent(psi_0201,0x8001,"OnSomeIpPrepareEventPhoneCallOperationResult");
SomeIpAddEventToEventGroup(peg_0201,Event_8001);
Field_9001=SomeIpAddField(psi_0201,0x9001,0x0002,-1);
SomeIpAddFieldToEventGroup(peg_0201,Field_9001);
#if 1
{
byte data[2];
data[0]=CallState.TGW_CallState;
data[1]=CallState.TGW_CallType;
writeEx(-3,1,"on timer UpdateCallState");
SomeIpSetData(Field_9001,2,data); //因为请求时候就要发送一次,所以要先给数值
}
/*
因为订阅成功后,FIELD会立即响应一条通知报文,但是如果没有数据库支持,此时负载域没有正确进行序列化,此时将无法通过IL完成报文的发送操作,所以此处要先对FIELD提供初始化数据,以实现序列化,并确保成功发送
*/
#endif
Field_Getter_0002=SomeIpAddMethod(psi_0201,0x0002,"OnMethod_GetCallState");
Method_1001=SomeIpAddMethod(psi_0202,0x1001,"OnMethodGNSSUpdateSet");
peg_0202=SomeIpAddProvidedEventGroup(psi_0202,1);
Field_0202_9001=SomeIpAddField(psi_0202,0x9001,-1,-1);
#if 1
{
byte data[129];
long index=0;
data[0]=GNSS_NMEA.TGW_NEMA_LEN;
for(index=0;index<128;index++)
data[1+index]=GNSS_NMEA.TGW_GNSS_NMEA[index];
writeEx(-3,1,"on timer UpdateCallState");
SomeIpSetData(Field_0202_9001,129,data); //因为请求时候就要发送一次,所以要先给数值
}
#endif
SomeIpSetProperty(peg_0202,"MulticastIp",ipGetAddressAsNumber("239.192.255.251"));
SomeIpSetProperty(peg_0202,"MulticastPort",30501);
SomeIpSetProperty(peg_0202,"MulticastThreshold",0);
//SomeIpSetProperty(Field_0202_9001,"CycleTimeMs",1000);
SomeIpAddFieldToEventGroup(peg_0202,Field_0202_9001);
SomeIpAddMethod(psi_0202,0x1001,"OnMethodGNSSUpdateSet");
peg_0203=SomeIpAddProvidedEventGroup(psi_0203,1);
SomeIpSetProperty(peg_0203,"MulticastIp",ipGetAddressAsNumber("239.192.255.251"));
SomeIpSetProperty(peg_0203,"MulticastPort",30501);
SomeIpSetProperty(peg_0203,"MulticastThreshold",0);
Event_0203_8001=SomeIpAddEvent(psi_0203,0x8001,"OnSomeIpPrepareEventSignalStrength");
SomeIpAddEventToEventGroup(peg_0203,Event_0203_8001);
SomeIpSetProperty(Event_0203_8001,"CycleTimeMs",1000);
SomeIpSetProperty(psi_0201,"MajorVersion",1);
SomeIpSetProperty(psi_0201,"MinorVersion",1);
ret=SomeIpSetProperty(psi_0201,"SDCyclicOfferDelay",1000);
if(ret)
{
writeEx(0,3,"TGW:SomeIpSetProperty(psi_0201,\"SDCyclicOfferDelay\",1000);");
}
SomeIpSetProperty(psi_0201,"MinorVersion",1);
SomeIpSetProperty(psi_0201,"SDTTL",3);
SomeIpSetProperty(psi_0201,"SDMinInitialDelay",10);
SomeIpSetProperty(psi_0201,"SDMaxInitialDelay",100);
SomeIpSetProperty(psi_0201,"SDMaxRepetition",3);
SomeIpSetProperty(psi_0201,"SDBaseRepetitionDelay",30);
SomeIpSetProperty(psi_0201,"SDMinResponseDelay",0);
SomeIpSetProperty(psi_0201,"SDMinResponseDelay",0);
SomeIpSetProperty(psi_0202,"MajorVersion",1);
SomeIpSetProperty(psi_0202,"MinorVersion",1);
ret=SomeIpSetProperty(psi_0202,"SDCyclicOfferDelay",1000);
if(ret)
{
writeEx(0,3,"TGW:SomeIpSetProperty(psi_0202,\"SDCyclicOfferDelay\",1000);");
}
SomeIpSetProperty(psi_0202,"SDTTL",3);
SomeIpSetProperty(psi_0202,"SDMinInitialDelay",10);
SomeIpSetProperty(psi_0202,"SDMaxInitialDelay",100);
SomeIpSetProperty(psi_0202,"SDMaxRepetition",3);
SomeIpSetProperty(psi_0202,"SDBaseRepetitionDelay",30);
SomeIpSetProperty(psi_0202,"SDMinResponseDelay",0);
SomeIpSetProperty(psi_0202,"SDMinResponseDelay",0);
SomeIpSetProperty(psi_0203,"MajorVersion",1);
SomeIpSetProperty(psi_0203,"MinorVersion",1);
ret=SomeIpSetProperty(psi_0203,"SDCyclicOfferDelay",1000);
if(ret)
{
writeEx(0,3,"TGW:SomeIpSetProperty(psi_0203,\"SDCyclicOfferDelay\",1000);");
}
SomeIpSetProperty(psi_0203,"SDTTL",3);
SomeIpSetProperty(psi_0203,"SDMinInitialDelay",10);
SomeIpSetProperty(psi_0203,"SDMaxInitialDelay",100);
SomeIpSetProperty(psi_0203,"SDMaxRepetition",3);
SomeIpSetProperty(psi_0203,"SDBaseRepetitionDelay",30);
SomeIpSetProperty(psi_0203,"SDMinResponseDelay",0);
SomeIpSetProperty(psi_0203,"SDMinResponseDelay",0);
SomeIpILControlStart();
setTimerCyclic(UpdateCallState,2000);
}
PSI端的EVENT,FILED,METHOD创建
dword SomeIpAddMethod( dword psiHandle, dword methodId, char onMethodRequestCallback[] ); // form 1
用于向PSI添加默认为RR类型的METHOD回调处理程序,其回调函数的接口形式为:
void <OnSomeIpMethodRequest>( dword methodHandle, dword messageHandle, dword messageResponseHandle )
dword SomeIpAddMethod( dword psiHandle, dword methodId, char onMethodRequestCallback[], long fireAndForget); // form 2
用于向PSI添加RR或是FF类型的接口处理程序,参数fireAndForget决定METHOD的类型:
1: A response is not sent
0: A response is sent (default behavior)void <OnSomeIpMethodRequest>( dword methodHandle, dword messageHandle, dword messageResponseHandle )
其中RR类型的回调处理接口定义形式为:
void <OnSomeIpMethodRequest>( dword methodHandle, dword messageHandle, dword messageResponseHandle )
FF类型的回调处理接口定义形式为:
dword SomeIpAddMethod( dword psiHandle, dword methodId, char onMethodRequestCallback[] )
long CreatePSI()
{
serviceHandle = SomeIpCreateProvidedServiceInstance(appEndpointHandle, 0x800 /*serviceId*/, 1 /*instanceId*/);
//首先创建一个PSI接口,PSI包含相应的EVENT,FILED,METHOD,EVENTGROUP资源,其中EVENT与FILED又从属于EVENTGROUP,所以从属于PSI的资源均要先添加到相应的PSI内容,再将EVENT与FILED划归相应的EVENTGROUP;
//PSI要与相应的AEP绑定,此绑定信息将自动填充至SD的Option中
ret=SomeIpSetProperty(serviceHandle,"MajorVersion",1);
ret=SomeIpSetProperty(serviceHandle,"MinorVersion",1);
ret=SomeIpSetProperty(serviceHandle,"SDTTL",300);//单位秒
ret=SomeIpSetProperty(serviceHandle,"SDMinInitialDelay",10);
ret=SomeIpSetProperty(serviceHandle,"SDMaxInitialDelay",30);
ret=SomeIpSetProperty(serviceHandle,"SDMaxRepetition",3);
ret=SomeIpSetProperty(serviceHandle,"SDBaseRepetitionDelay",30);
ret=SomeIpSetProperty(serviceHandle,"SDMinResponseDelay",10);
ret=SomeIpSetProperty(serviceHandle,"SDMaxResponseDelay",30);
ret=SomeIpSetProperty(serviceHandle,"SDMaxRepetition",3);
/*
针对PSI相关的参数配置,涉及:
SD服务事件流程的参数:初始化延时,OFFERSERVICE重复次数,SD响应的延时参数,TTL等参数等*/
//create a provided service instance
SomeIpSetProperty(serviceHandle, "SDCyclicOfferDelay", 1000); //service is announced every second
SomeIpSetProperty(serviceHandle, "SDTTL", 3); //service offer is valid 3 seconds
methodCall=SomeIpAddMethod(serviceHandle,0x5236,"OnPrepareEvent");
/*
对PSI进行相应的属性配置
*/
providedEventgroupHandle = SomeIpAddProvidedEventGroup(serviceHandle, 1 /*eventgroupId*/);
SomeIpSetProperty(providedEventgroupHandle , "MulticastIp", IpGetAddressAsNumber("239.192.255.251"));
SomeIpSetProperty(providedEventgroupHandle , "MulticastPort", 30490);
SomeIpSetProperty(providedEventgroupHandle , "MulticastThreshold", 2);
/*
向PSI中填充相应的EVENTGROUP资源
*/
gProvidedEventHandle = SomeIpAddEvent(serviceHandle, 0x9009/*eventId*/, "OnPrepareEvent");
SomeIpAddEventToEventgroup(providedEventgroupHandle, gProvidedEventHandle);
SomeIpSetProperty(gProvidedEventHandle,"CycleTimeMs",500);
/*
向PSI添加EVENT事件资源,并将EVENT添加到指定的EVENTGROUP中,一个PSI可以包含多个事件组,每个事件组均有其唯一的EVENTGROUP编号
SomeIpSetProperty(gProvidedEventHandle,"CycleTimeMs",500); 事件分为周期性事件,与触发型,为了测试方便,本处将该事件设置为周期性事件
*/
pf_filed=SomeIpAddField(serviceHandle,0x8089,0x3396,0x2562);
SomeIpAddFieldToEventGroup(providedEventgroupHandle,pf_filed);
ret=SomeIpSetData(pf_filed,100,buffer);//添加FILED负载数据内容
Method_Getter=SomeIpAddMethod(serviceHandle,0x3396,"OnSomeIpMethodRequest_RR");
Method_Setter=SomeIpAddMethod(serviceHandle,0x2562,"OnSomeIpMethodRequest_FF");
/*
向PSI添加FILED资料,FILED无相应的回调处理程序接口,其SomeIpAddField返回值即为该FILED的MESSAGEHANDLE接口,可能通过此值处理其响应负载数据内容
如果不对GETTER&SETTER重新设置相应的请求处理回调,IL会自动使用默认数据内容进行响应,这个一般需要数据库的支持;如果需要改为FILED默认的处理接口,需要使用SomeIpAddMethod()
*/
}
//PSI端刚相应的事件被触发后,将进入此回调函数中,在此接口可处理EVENT的负载内容,添加要发送的数据内容
void OnPrepareEvent1 (DWORD eventHandle, DWORD messageHandle)
{
// this function is called before the Event is sent. Parameters can be specified here.
}
//如果为RR类型METHOD,需要设置为此回调接口函数,其中messageResponseHandle 为响应的SOMEIP数据包的配置接口
void OnSomeIpMethodRequest_RR( dword methodHandle, dword messageHandle, dword messageResponseHandle ) // form 1
{
}
//如果为FF类型METHOD,需要设置为此回调接口函数
void OnSomeIpMethodRequest_FF( DWORD methodHandle, DWORD messageHandle ) // form 2
{
}
CSI端的EVENT,FILED,METHOD相关资源的创建
dword SomeIpCreateMethodCall( dword csiHandle, dword methodId, char onSomeIpMethodResponse [] ); // form 1
This function creates a method call for the consumer. By means of the return value of the function, the method parameters can be set using SomeIpSetValue.... The method is then called using SomeIpCallMethod.
创建RR类型的请求,当调用SomeIpCallMethod时,将以RR的请求方式发送METHOD请求
dword SomeIpCreateMethodCall( dword csiHandle, dword methodId ); // form 2
This function creates a method call for the consumer. By means of the return value of the function, the method parameters can be set using SomeIpSetValue.... The method is then called using SomeIpCallMethod.
创建FF类型的请求,当调用SomeIpCallMethod时,将以FF的请求方式发送METHOD请求
dword SomeIpCreateMethodCall( dword csiHandle, dword methodId, char onSomeIpMethodResponse [], char onSomeIpMethodError []) ); // form 3
This function creates a method call for the consumer. By means of the return value of the function, the method parameters can be set using SomeIpSetValue.... The method is then called using SomeIpCallMethod.
创建RR类型的请求,当调用SomeIpCallMethod时,将以RR的请求方式发送METHOD请求,并添加了错误响应的处理接口回调
dword SomeIpCreateFieldConsumer( dword csiHandle, long notificationId, long getterId, long setterId, char onFieldNotificationCallback[] );
功能:
This function adds a Field Consumer to a Consumed Service Instance that was created by SomeIpCreateConsumedServiceInstance.
When a suitable field notification is received, the passed Notification Callback is called (see <OnSomeIpFieldNotification>).
A Field Consumer can be removed again using the SomeIpRemoveFieldConsumer function.
向CSI接口添加FILED资源信息,并回调该FILED对应Notification处理接口,但是如果期望处理SETTER与GETTER的请求功能,
需将SETTER与GETTER以普通的METHOD方式进行添加,并明确处理回调函数即可
void <OnSomeIpMethodResponse>(dword methodCallHandle, dword messageResponseHandle );
void <OnSomeIpMethodError>( dword methodCallHandle, dword messageErrorHandle );
//Method的响应处理程序的接口与错误响应的处理接口
//methodCallHandle:Handle of the Event that triggered the callback, see SomeIpAddMethod.
//messageErrorHandle:Message handle of the SOME/IP error message.
on start
{
// open application endpoint
aep = SomeIpOpenLocalApplicationEndpoint(17, 50002);
ret=SomeIpSetProperty("SDMulticastIp",ipGetAddressAsNumber("224.0.0.255"));
ret=SomeIpSetProperty("ClientId",0x64);
ret=SomeIpSetProperty("SDMulticastPort",30490);
/*
创建CSI所有AEP接口资源,相关的IP信息,将添加到订阅SD服务的OPTION中
同时设置CSI全局的信息:
1.ClientID 定义当前ECU的CLIENTID信息
2.SD使用的组播地址与端口信息
*/
// create Service Instance
csi = SomeIpCreateConsumedServiceInstance(aep,257,1);
ret=SomeIpSetProperty(csi ,"SDCyclicRequestDelay",1000);//单位ms
ret=SomeIpSetProperty(csi ,"SDTTL",300);
ret=SomeIpSetProperty(csi ,"SDMinInitialDelay",10);
ret=SomeIpSetProperty(csi ,"SDMaxInitialDelay",30);
ret=SomeIpSetProperty(csi ,"SDMaxRepetition",3);
ret=SomeIpSetProperty(csi ,"SDBaseRepetitionDelay",30);
/*
创建CSI接口实现,定义消费端需要的SERVICEID与INSTANCEID的信息,此信息将填充至FINDSERVICE SD的服务中;
并对FINDSERVICE相关的行业属性进行赋值操作:如FINDSERVICE的TTL生命周期,SD的初始化延时参数,重复发送的次数与重复发送基础延时时长;
如果期望FINDSERVICE周期性发送,可配置SomeIpSetProperty(csi ,"SDCyclicRequestDelay",1000);
*/
// create Eventgroup
ceg = SomeIpAddConsumedEventGroup(csi,1);
/**/
ret=SomeIpSetMulticastReceiverEndpoints(ceg,ipGetAddressAsNumber("224.0.0.236"),30490);
// create Event Consumer
cev = SomeIpCreateEventConsumer(csi,0x9001,"CallbackEvent1");
method=SomeIpCreateMethodCall(csi,0x5236,"OnMethodResponse");//添加普通的METHOD请求接口,并明确相应的回调处理函数接口
SomeIpCreateFieldConsumer(csi,0x8009,0x3396,0x2562,"OnSomeIpFieldNotification");
method4=SomeIpCreateMethodCall(csi,0x3396,"OnMethodResponse");//定义一个R类型的METHOD,对应FILED的GETTER
method5=SomeIpCreateMethodCall(csi,0x2562);//定义一个FF类型的METHOD,对应FILED的SETTER
}
on key 's'
{
SomeIpSetData(method4,elcount(data),data);
SomeIpCallMethod(method4);//调用CALL接口发送相应的METHOD请求,此时发送的RR请求类型
}
on key 'r'
{
SomeIpSetData(method5,elcount(data),data);
SomeIpCallMethod(method5);//调用CALL接口发送相应的METHOD请求,此时发送的FF请求类型
}
事件组的发送方式
IL提供了两种发送方式:
1.全程只使用单播方式发送事件或是FILED等订阅报文内容
2.当订阅此服务的数量超过指定数量后,即转换为多播方式发送,在此之前使用单播方式发送
SOMEIP参数的序列化转换依据
地
字符串序列化之Byte-Order(字节顺序)
BOM一般添加在字符前,表示字符类型,如果是UTF-16或是UTF-32(即一个字符使用位数)字节排序方式与字符类型
SOMEIP字符串的序列化标准
1.定长字符串时:因为收发双方都约定好字符串的长度,所以传送的时候可以不带字符串的长度
2.不定长字符串时:在字符串前加上长度标识(8/16/32位)的字符串长度标识
字符串发送序列化方式:
**[可选报文长度]+BOM+字符串内容+'\0' 其中EOL字符是算长度的。**
[可选报文长度]=BOM数量+实际字符量+1位结尾EOL
Payload区域内的数据传送顺序无强制要求,需客户定义
SD服务的处理逻辑
1.针对ConsumerServiceInstance端SD处理逻辑
注:
1.FINDSERVICE发送是组播地址进行发送
1.FINDSERVICE发送是组播地址进行发送
1.FINDSERVICE发送是组播地址进行发送
1. 【DOWN模式】设备刚启动后,IP变化,IP失效,或是相应的服务不再需要,如消费端调用SomeIpSDRelease(csi),释放相应的服务的请求后,均进入DOWN模式。
2. 当Client准备好通信后,将生成一个随机延时时长,【如果在Initial Wait Phase阶段收到相应的offerService将进入Main环节】
3. 如果【Initial Wait Phase】没有收到OfferService消息,将进入 Repetition Phase环境,如果在此环节中收到相应的OfferService将直接进入Main环节
4. 如果在【Repetition Phase】环节没有收到相应的OfferService事件,将在完成指定的FIND Service事件后,直接进入Main环节,此时将停发相应的FIND SERVICE事件,进入静默状态
5. 如果【main】环节收到相应的OfferService将触发相应的服务订阅服务。【如果该服务不提供Event或是FILED服务的时候,则表示此服务有效,Consumer端将更新TTL的计时】
服务提供端的流程特点:流程固定且不会被中断,但是流程中可以处理与响应相应的SD订阅的服务
无EVENT与FIELD无需订阅,但是相应的服务也其有效的TTL期间才有效,所以CLIENT只能接收SERVER的OFFERSERVICE后,并在TTL有效期内才能使用该服务提供的METHOD,GETTER,SETTER等
1. 【DOWN模式】服务不可用的时候进入此阶段
2. 【Intitial Wait Phase】在生成的随机初始化时长阶段中,不外发OFFERSERVICE SD服务,也不会对任何FINDSERVICESD 请求做出响应,但对订阅相关的请求作出响应如(Stop)SubscribeEventGroup SD要做出响应与处理
3. 【Server中的Repetition Phase】是强制执行的过程,如果此过程中收到服务的订阅服务将使用【Unicast单播地址】进行ACK或是NACK响应;但是如果收到FINDSERVICE不作出响应
4. 在【Main】环节如果【OfferCyclicDelay】参数不为0的话,会周期发送相应的OFFERSERVICE的SD服务消息,但是如果此值为0,将停发OFFERSERVICE SD服务
1.如果在【MAIN】环节收到FINDSERVICE时,将以Unicast单播方式回复OFFERSERVICE
2.如果在【MAIN】环节收到订阅SD,回复SD ACK,并启动该SD订阅的服务的TTL时钟,如果时钟超时,将表示CLIENT不再订阅此服务,SERVER无需向CLIENT反馈任何信息,并停止相关服务的输出
3.如果在【MAIN】环节收到Stop SubscribeEventGroup服务,停止相应的服务TTL TIMER,无需做出任何回应
在这里插入代码片
问题汇总
SessionID的使用规则
** PSI端维护策略**
**SD服务的维护策略**
1.组播单独维护一个SESSIONID,每次输出offerService后自动加1
2.SD单播也单独维护一个SESSIONID,如单播发送OFFERSERVICE,SUBSCRIBE ACK时候使用此值,每成功发送一次加1
3.EVENT与FILED两种NOTIFICATION单独一个SESSIONID,每发送一次相应的NOTIFICATION消息,即加1
简述:服务端每个PSI需维护一个组播SESSIONID,同时针对每个单播(注意是每个单播服务维护一个SESSIONID),每个订阅的事件组维护一个SESSIONID(针对同一事件组被多个消费端订阅的时候,将针对每个消费端的单播放服务维护一个SESSIONID)
如图因为PSI端的OFFER使用的是组播,故其单独维护一个组播的SESSIONID值
SD的单播,维护一个单独的SESSIONID,即便相同的事件组,也会根据每个单播地址生成一个独立的SESSIONID,单独进行维护,所以在回复订阅ACK时候,使用不同的SESSIONID
CSI端维护策略
**SD服务的维护策略**
1.组播单独维护一个SESSIONID,每次输出FINDService后自动加1
2.SD单播也单独维护一个SESSIONID,如单播发送SUBSCRIBE时候使用此值,每成功发送一次加1
3.所有METHOD事件共享一个SESSIONID,该值将与CLIENTID组成相应的REQUESTID值,发送至服务提供方,并接收相同的REQUESTID的Reponse包作为响应。
ClientID使用场景
仅用的method服务中,其他服务中不使用此值,如果Event,Filed的Notification通知消息的时候,消息从SERVER主动向Client发送,此时ClientID值为0.
SD服务中全程此ClientID为0
只有Method请求过程中,Request过程中填入此值,并将Method维护的SessionID加1,组合成请求包,发送于SERVER,SERVER响应时直接复制Request中的RequestID内容,作为回应,一一对应。
注:
每个CSI中的METHOD只维护一个共享的SESSIONID,且不区分method的类型,不管是RR还是FF类型的Request中的SESSIONID均进行递加运算*
如果获取SD包中的FLAG参数信息
SOMEIP-IL未提供相应的读取FLAG的参数,故只能使用ethernetpacket接口来进行读取操作,代码如下
on ethernetPacket *
{
ip_Address ipaddr;
if(this.someip.IsAvailable())
{
//this.someip.
if(this.udp.source.IsAvailable())
this.GetSourceIPAddress(ipaddr);
else
return;
if(ipaddr.IPV4Address==ipGetAddressAsNumber("192.168.1.3")&&0xFFFF8100==swapDWord(this.someip.dword(0)))
{
char ip[20];
ipaddr.PrintAddressToString(ip);
writeEx(-3,1,"Reboot=%x Session=%X",this.someip.byte(16),swapDWord(this.someip.dword(8)));//byte(16)即为Reboot所在 Flag字节数据内容
}
}
}
或是通过SomeIpGetData来获取SomeIp的负载数据内容,因为在SD服务中除了SOMEIP头部信息外,Flag也作为负载数据进行读取
void OnSomeIpMessage( dword messageHandle )
{
ip_Address ip;
char msg[200];DWORD nbrOfEntries;
BYTE i;
CHAR valuePath[255];
DWORD entryType;
DWORD nbrOfOptions;
DWORD optionType;
byte payload[500];
long index=0;
byte flag=0x00;
//针对的SD协议包的数据负载内容读写操作,其他METHOD,EVENT,FILED等负载内容需要数据库支持才能完成读写操作
if(SomeIpGetMessageId(messageHandle) == 0xFFFF8100)
{
SomeIpGetData(messageHandle,elcount(payload),payload);
flag=payload[0];//因为网络传输是大端传端,所以负载的第一个字节即为Reboot内容
}
函数使用
手动生成SOMEIP包
项目 | Value |
---|---|
SomeIpCreateMessage | Creates a SOME/IP message.生成SOMEIP的包头 |
SomeIpOutputMessage | Sends a SOME/IP message.单独打包一条SOMEIP包并发送 |
SomeIpPostMessage | Posts a SOME/IP message.将所有的SOMEIP的包打包到一条SOMEIP报文中并发送出去 |
SomeIpReleaseMessage | Deletes a SOME/IP message. |
dword SomeIpCreateMessage( dword messageId, dword requestId, dword protocolVersion, dword interfaceVersion, dword messageType, dword returnCode ); // form 1
dword SomeIpCreateMessage( dword bufferLength, byte buffer[] ); // form 2
dword SomeIpCreateMessage( dword bufferLength, byte buffer[], dword offset ); // form 3
long SomeIpOutputMessage( dword aepHandle, dword remoteIPv4Address, dword remotePort, dword messageHandle ); // form 1
long SomeIpOutputMessage( dword aepHandle, IP_Endpoint remoteIPEndpoint, dword messageHandle); // form 2
至于是UDP包还是TCP包,取决于AEP的定义,如果TCP包应该之前应该已经建立连接
long SomeIpPostMessage( dword aepHandle, dword remoteIPv4Address, dword remotePort, dword messageHandle ); // form 1
long SomeIpPostMessage( dword aepHandle, IP_Endpoint remoteIPEndpoint, dword messageHandle ); // form 2
该函数也是向UDP或是TCP包中添加SOMEIP数据包,只是此函数会先将包添加到UDP/TCP包,但不立即发送,而是在调用这个函数的外围函数结束的时候发送!
**long SomeIpReleaseMessage( dword messageHandle );**手动生成的包使用完成后记得释放。
on key 's'
{
DWORD messageId = 0x12340004; // service ID = 0x1234, method ID = 0x0004
DWORD requestId = 0; // client ID = 0, session ID = 0
DWORD protocolVersion = 1;
DWORD interfaceVersion = 1;
DWORD messageType = 0x2; // notification message
DWORD returnCode = 0; // not available
DWORD aep = 0; // application endpoint handle
DWORD messageHandle = 0; // handle of the created SOME/IP message
BYTE payload[5]; // the message payload
DWORD count = 0; // a simple counter
// initialize the payload
count = 0;
payload[count++] = 0x11;
payload[count++] = 0x22;
payload[count++] = 0x33;
payload[count++] = 0x44;
payload[count++] = 0x55;
// open application endpoint
aep = SomeIpOpenLocalApplicationEndpoint(17, 50002);
// create the SOME/IP message itself and set the message payload
messageHandle = SomeIpCreateMessage(messageId,requestId,protocolVersion,interfaceVersion,messageType,returnCode);
SomeIpSetData(messageHandle,elcount(payload),payload);
//需要填充相应的数据后,SOMEIP包的才有效,否则不会被发出去
// send the SOME/IP message
SomeIpOutputMessage(aep,0xFFFFFFFF,40001,messageHandle);
SomeIpPostMessage(aep,0xFFFFFFFF,40002,messageHandle);
SomeIpPostMessage(aep,0xFFFFFFFF,40001,messageHandle);
SomeIpPostMessage(aep,ip_endpont(UDP:192.168.25.25:30501),messageHandle);
SomeIpPostMessage(aep,ip_ipaddress(192.168.25.25),30501,messageHandle);
//aep决定了发送包的类型,如果aep为TCP连接将发送是TCP包,否则为UDP包。
// release the some IP message
SomeIpReleaseMessage(messageHandle);
}
OnSomeIpMessage
对于类似SomeIpPostMessage()接口发送的报文,因为一条网络报文中含有多条SOMEIP报文,接收端会对接收到的报文进行分解每条SOMEIP报文均会触发一条OnSomeIpMessage事件,故可以在此事件中所有接收到的报文进行处理!!!
void OnSomeIpMessage( dword messageHandle )
{
#if 1
DWORD nbrOfEntries;
BYTE i;
CHAR valuePath[255];
DWORD entryType;
DWORD nbrOfOptions;
DWORD optionType;
dword SessionID;
dword Flags;
if(SomeIpGetMessageId(messageHandle) == 0xFFFF8100)
{
SessionID=SomeIpGetRequestId(messageHandle)&0xFFFF;
Flags=SomeIpGetValueDWord(messageHandle,"Flags");
writeEx(outWindow_TGW,1,"\nSESSIONID=%d Flags=%X",SessionID,Flags);
nbrOfEntries = SomeIpGetValueDWord(messageHandle, "Entry");
for(i=0; i<nbrOfEntries; i++)
{
snprintf(valuePath, elCount(valuePath), "Entry[%d]", i);
entryType = SomeIpGetValueDWord(messageHandle, valuePath);
switch(entryType)
{
case 0x00 /*FindService*/:
snprintf(valuePath, elCount(valuePath), "Entry[%d].FindService.ServiceID", i);
writeEx(-3,1,"FindService with SESSIONID= %d", SessionID);
break;
case 0x01 /*OfferService*/:
snprintf(valuePath, elCount(valuePath), "Entry[%d].OfferService.ServiceID", i);
writeEx(-3,1,"OfferService with SESSIONID= %d", SessionID);
break;
case 0x06 /*Subscribe*/:
snprintf(valuePath, elCount(valuePath), "Entry[%d].Subscribe.EventgroupID", i);
write("Subscribe with SESSIONID= %d", SessionID);
break;
case 0x07 /*SubscribeAck*/:
snprintf(valuePath, elCount(valuePath), "Entry[%d].SubscribeAck.EventgroupID", i);
writeEx(-3,1,"SubscribeAck with SESSIONID= %d", SessionID);
break;
}
}
}
else
{
writeEx(-3,1,"OnSomeipMessage:MessageID=%x SessionID=%x",SomeIpGetMessageId(messageHandle),SomeIpGetRequestID(messageHandle));
}
#endif
}