使用以太网时, 通信不是确定性的, 因为冲突, 这可能发生在具有集线器的网络上的多个主机之间, 或者因为 switch 情况下的未知延迟。
以太网协议不允许确定性通信因为可能会发生冲突并支持通过机制 CSMA/CD (载波侦听多址访问/冲突检测)。
RTnet
是一个协议栈, 运行在以太网层和应用层(或 IP 层)。它的目标是, 通过使用时间 intervals
(时隙), 是为了进行确定性的通信, 通过禁用冲突检测CSMA/CD, 并防止缓冲数据包在网络中。RTnet
是为在 Linux
内核上运行而开发的软件使用 RTAI
或 Xenomai
实时扩展。它利用实时 kernel
扩展来确保通信堆栈上的确定性。为此, 与此协议相关的所有说明都使用实时内核函数, 而不是 Linux
的内核函数, 后者将执行时间的延迟和中断的延迟, 其中提供确定的通信。
Rtnet
使用时分多路复用 TDMA
(时分倍数Access) 以避免通信冲突, 主服务器在每个循环的开始, 一个包含来自要同步的全局时钟。发送同步帧并包含编码为 4 的周期编号 bytes
, master
的参考时间值(以纳秒为单位)和进行传输时的参考时间的值, 则 value
有助于减少全局时钟的偏差。这同步消息包含以下数据:为了弥补缺失集中式主从, 二级主服务器 (backup-master) 可以是通过为 backup master
预订额外的 slot
来建立。如果 primary master
倒下, secondary master
在服用考虑与上一帧同步的偏移。当 primary master
重新投入服务, 它与活动的 secondary master
, 则 secondary master
被禁用。
Rtnet
协议栈包含一个物理部分到传输层 OSI
模型。它是专门为实时工作而开发的内核 RTAI
和 Xenomai
。确保通信的确定性应用程序, 以太网控制器应用程序软件使用的所有功能都满足硬性实时约束。因此, 网络层协议和传输尤其必须实现以使用 Linux
的实时内核, 而不是常用的 Linux
内核。
物理层由以太网控制器支持, 需要使用来自 Linux
的特定驱动程序。处理内存、中断处理机制或屏蔽中断需要由实时内核执行的操作, 以确保确定性。在以太网驱动程序中, 应尽可能精确地检测发射和接收的瞬间。从材料角度来看, 可以使用任何以太网控制器, 并可以支持其他物理层(如Firewire)。管理控制器以非实时方式执行初始化、设置和关闭操作, 因此应特别注意传输和接收功能。在传输时, 应保存全局时钟的值, 而在接收函数中, 应在接收时保存全局时钟的值, 以便精确控制抖动。
以太网作为标准操作不能提供硬实时通信, 无论是在基于中继器的网络上, 还是在这有碰撞的风险。提供的服务质量 IEEE 802.1q 为此问题提供了一个很好的解决方案, 但是交换机的集中化布线成本高昂。数据链路协议的 Rtnet
由名为 Rtmac
的内核模块提供, 其中包含一个模块 TDMA
。TDMA
模块管理网络上的通信(同步、循环时间等)虽然此层是可选的堆栈 Rtnet
的扩展, 它带来了确定性的媒体访问协议:
Rtnet
的 Rtmac
层是一个提供以下服务的模块:
Rtnet
在数据链路层使用时分接入网络, 以防止发生碰撞。该协议同步该网段使用主从通信, 并定义数据传输到传输的同步消息的时间周期性地。如果一个节点在启动时也可以加入网络, 如果他知道他的时间访问权, 在节点或服务器上手动配置在网络节点上就地配置 (rtcfg)。一旦此参数获取的 Node
将通过以下方式评估返回网络的时间向主同步发送查询, 主同步将通过以下方式响应在数据包发送的计时信息中包括可以计算返回时间。
UDP/IP 和 TCP/IP 网络和传输层的堆栈支持, 通过简化路由和优化的过程碎片。ARP (Address Resolution Protocol) 协议适用于仅在初始化时操作。在通讯方面对于总线来说, 这些协议可能是不必要的, 但却是相关的与外部网络的通信, 通常是非实时的。IP
协议实现运行在实时内核和支持分片发送超过 MTU (Maximum . MTU)的报文传输设备。要执行路由, 需要使用两个表, 第一个表表中包含主机的 IP
地址, 即来宾路由表在局域网内可达。第二个表(可选)使用网关地址到其他网络的实时, 允许建立具有更复杂结构的网络。路由表的内容类似于标准 IP
栈的 ARP
表。对于 Rtnet
来说表用于路由过程, 但情况并非一定如此用于标准电池。UDP 和 TCP 在 IP 层之上实现(版本4), UDP
用于硬实时传输。其次是 TCP
最近实施的目的是与要素进行沟通在不运行 Rtnet
的网络中, TCP
要复杂得多(在100多个rfc中有描述)。因此它的实施已大大简化, 因为它的用途是有限的。UDP
协议部分, 使用默认协议建立实时通信在两个应用程序之间。Rtcfg
是为 Rtnet
定义的协议有效配置网络。为此, 使用网络节点作为并向其他节点(客户端)发送配置信息。由于虚拟接口的存在, 可以运行所有网络层协议, 并在更高标准的 Linux
上实现内核。对于有限的通信网络节点也是可行的不使用路由协议和传输(套接字类型RAW
)。
注意在加载 rtnet
驱动时, 需先对 rtnet
做如下配置
对配置文件进行简要说明, 解释如下
配置选项 | 描述 |
---|---|
RT_DRIVER | rtnet 驱动名称 |
RT_DRIVER_OPTIONS | rtnet 驱动索引 |
REBIND_RT_NICS | rtnet 驱动设备 |
IPADDR | rtnet 驱动加载后的静态 ip |
NETMASK | rtnet 驱动加载后的掩码 |
配置文件路径为 /usr/xenomai/etc/rtnet.conf (可通过 vim
编辑器对配置进行修改)
# RT-NIC driver
RT_DRIVER="rt_igb"
RT_DRIVER_OPTIONS="1"
REBIND_RT_NICS="0000:01:00.2" # 此项为支持 rt_igb 的 pci 设备的具体位置信息
IPADDR="192.168.1.244" # 此项需根据实际网络环境进行配置
NETMASK="255.255.255.255" # 此项需根据实际网络环境进行配置
#TDMA_MODE="master"
#TDMA_SLAVES="127.0.0.1"
#TDMA_CYCLE="5000"
#TDMA_CONFIG="${prefix}/etc/tdma.conf"
对必要配置选项针对不同设备, ip 网段配置完成后, 取消 TDMA 相关配置(在配置文件中注释掉 TDMA 相关选项即可)
# 加载 rtnet 驱动
rtnet start
# 卸载 rtnet 驱动
rtnet stop
# 类似 ifconfig 命令, 显示 rtnet 下配置的网口信息
rtifconfig --help
# Usage:
# rtifconfig [-a] [<dev>]
# rtifconfig <dev> up [<addr> [netmask <mask>]] [hw <HW> <address>] [[-]promisc]
# rtifconfig <dev> down
# example:
# 此项示例以 ip : 192.168.1.244 仅作为示例说明, 实际应用需根据实际网络环境进行配置
# 启用 rteth0 网卡并将网卡 ip 以及 netmask 配置如下
# rtifconfig rteth0 up 192.168.1.244 netmask 255.255.255.255
# 禁用 rteth0 网卡
# rtifconfig rteth0 down
# 类似 route 命令, 显示 rtnet 下配置的路由信息
rtroute --help
#Usage:
# rtroute
# rtroute solicit <addr> dev <dev>
# rtroute add <addr> <hwaddr> dev <dev>
# rtroute add <addr> netmask <mask> gw <gw-addr>
# rtroute del <addr> [dev <dev>]
# rtroute del <addr> netmask <mask>
# rtroute get <addr> [dev <dev>]
# rtroute -f <host-routes-file>
# example:
# 此项示例以 ip : 192.168.1.244, mac : C8:6B:BC:80:08:EE 仅作为示例说明, 实际应用需根据实际网络环境进行配置
# 向静态路由表中添加如下路由配置信息:
# rtroute solicit 192.168.1.244 dev rteth0
# rtroute add 192.168.1.244 C8:6B:BC:80:08:EE dev rteth0
rtping 192.168.1.244
用户可根据自己需要通过 rtifconfig 进行网口的 ip 、netmask、 up、down 等或 rtroute 进行路由操作, 如 add、del、get 等
详情请查阅 RTnet 示例程序说明
flowchart TD
Start[开始]
services_init[服务器初始化]
create_sub_rt_thread[创建实时子线程]
ctrl_c_or_system_error[退出信号或系统报错]
send_data[发送数据包]
recv_data[接收数据包]
filter_data[过滤数据包]
End[结束并退出]
Start --> services_init --> create_sub_rt_thread --> ctrl_c_or_system_error
ctrl_c_or_system_error --> |是|End
ctrl_c_or_system_error --> |否|recv_data --> filter_data
filter_data --> |是|send_data --> ctrl_c_or_system_error
filter_data --> |否|ctrl_c_or_system_error
flowchart TD
Start[开始]
client_init[客户端初始化]
create_sub_rt_thread[创建实时子线程]
ctrl_c_or_system_error[退出信号或系统报错]
send_data[发送数据包]
recv_data[接收数据包]
filter_data[过滤数据包]
parse_data[解析数据包]
End[结束并退出]
Start --> client_init --> create_sub_rt_thread --> ctrl_c_or_system_error
ctrl_c_or_system_error --> |是|End
ctrl_c_or_system_error --> |否|send_data
send_data --> recv_data --> filter_data
filter_data --> |是|parse_data --> ctrl_c_or_system_error
filter_data --> |否|recv_data
当固定发送定长数据至网卡系统平均耗时即以相关数据统计分析
平均耗时/ns | 标准差 | 变异系数 | |
---|---|---|---|
rtnet | 45620.72 | 1421.41 | 0.0311571 |
no_rtnet | 79528.26 | 11009.68 | 0.1384373 |
此项数据对比表明, 当使用 rtnet
驱动操作实时网卡时, 发送相同数据至网卡的平均耗时较低, 同时每次耗时较为接近, 标准差偏离较小, 耗时稳定, 而使用 no_rtnet
驱动时, 平均耗时较高, 而且波动相对较大, 发送时长不稳定