CA工作机制

作者: 七彩布谷 | 来源:发表于2020-12-05 22:20 被阅读0次

    channel access是epics用来进行消息通信的专属协议,是典型的客户端/服务端模式。由于epics是处理分布式控制系统的平台,其物理拓扑结构就像标志性logo表示的一样,clients和servers分散在不同位置,他们之间的数据交换通过消息总线传递。

    基本结构

    • server
      当启动ioc的时候,也就启动了服务端,epics连接设备,进行数据交互,更新数据库,逻辑运算。
    • client
      通常的客户端为各种监视程序,比如alarmer,archiver,或者基于ca库的模拟程序等。
    • repeater
      中继器,用来转播udp广播的,确保host上的多个client、server能够接收到数据包。

    网络协议

    ca协议是基于tcp/ip协议栈的,因此也遵循基本的网络约定。使用tcp进行数据交换,使用udp进行广播。

    端口占用

    在ca协议中,最重要的是serverPort和repeaterPort,前者用于监听client的名字搜索,并且发送心跳给repeater;后者转发搜索、心跳等广播数据报文。

    EPICS_CA_SERVER_PORT = 5064
    EPICS_CA_REPEATER_PORT = 5065
    

    此外,server端还占有一个用于建立虚拟回路的端口,该端口号不确定。

    物理信道

    ca秉承资源最小化的原则,提出了虚拟回路virtual circuit的概念。虚拟回路是数据交换的真实物理通道,单个client与单个server之间只存在一个tcp连接,并不以pv数量的多少增长。这样设计的考虑点,在于不会过度浪费socket的资源,实现资源的复用性。

    数据包

    在分布式控制系统中,单个信号的数据量是相当小的,单次通信的流量主要消耗在报文头。针对这种小数据包的场景,ca协议引入了缓存buffer。对于每个虚拟回路都建立一个发送缓存队列,将所有的ca数据包都暂存起来,直到达到预定容量、预定超时、或者用户强制发送,则将数据打包,通过socket信道一次性发送。

    数据包头

    数据以典型的tcp字节流形式组织,数据包头有固定格式,固定长度为16字节。除了指令ID和内容长度,其他数据块的内容可能根据指令ID不同而不同,但不违背数据块长度约束。具体指令可以参考ca协议

    数据类型

    ca协议支持基本的数据类型,以及对waveform支持的数组类型

    • 字节类型:bi、mbbi等
    • short:内部使用
    • int:内部使用
    • float:内部使用
    • double:ai、ao等
    • 字符数组:waveform

    ps. 在虚拟回路概念下,实际收包可能是多个指令数据包的组合,可能某个包被截断,因此接收方处理recvBuffer数据时特别注意按长度拆包解包。

    数据通信

    Beacon消息

    服务端启动后,将包含ip地址的udp数据包(CA_PROTO_RSRV_IS_UP),通过5064端口(中继到repeater的5065端口)广播出去。这样不间断的对外发送心跳,是一种典型的keepalive机制,让网络上客户端得知服务端还存活。如果客户端超时未接收到beacon心跳指令,其监听的回调函数得知事件后,发送echo指令CA_PROTO_ECHO(tcp)确认服务端是否真的断线。如果超时未收到服务端的确认回复,那么客户端主动断开与服务端的socket,释放通道分配的资源(包括线程,网络资源,数据结构等)。

    Search消息

    客户端启动后,会主动搜索服务程序端口,即会产生类似“pv_XXX在哪里”的搜索报文。搜索消息(CA_PROTO_SEARCH)是通过5064端口,以UDP的形式广播出去的。收到广播的服务器,会查询自身数据库中是否包含对应的pv。如果没有,直接忽略。如果有,则将自身的ip地址和端口通过5064端口,以UDP的形式回复给客户端。
    client收到回复,则建立起与服务端的tcp虚拟回路信道。对于多个pv在同一server上,一旦某个pv触发建立了信道,其余的pv将复用这条通道。

    建立Channel

    一旦client与server的虚拟回路形成,client会在这条信道上发送CREATE_CHANNEL消息(CA_PROTO_CREATE_CHAN),希望建立pv的通道。create消息包含client的pv名字,以及channelID。建立成功,server会回复包含serverID(SID)、channelID(CID)、pv数据类型,以及数据个数的消息,通常一条虚拟回路仅分配一个serverID。并且在通信过程中保持不变,除非断线重连。

    注册Repeater

    repeater的扮演者中继器的角色,广播消息都会通过它转发。repeater是独立的进程,通常是被动创建的。client启动时,在和host交互之前,通常会试探性的绑定到repeater的5065端口,探测repeater是否存在。如果绑定失败,client假设repeater已经存在,可以正常通信。绑定成功,则是repeater不存在,client触发repeater进程的创建。
    repeater创建后,client发送包含IP地址的注册消息(CA_REPEATER_REGISTER),以后repeater收到的消息都会转发到该client上。

    订阅数据

    channel建立以后,client发送包含订阅ID的tcp消息(CA_PROTO_EVENT_ADD)到server,订阅该pv的数据变更。变更类型有数值、警告和日志更新。在server端注册成功后,会回复成功消息。如此,关于pv数据的订阅发布模型建立,相关的数据变更将会通知到client。

    读/写请求

    当client有读写请求的时候,发送CA_PROTO_READ_NOTIFYCA_PROTO_WRITE_NOTIFY消息,等待server处理完成。每次消息会包含递增的请求ID(IOID),识别不同的请求。

    流量控制

    当client的处理能力不足以消化收到的数据更新时,会发送CA_PROTO_EVENTS_ONFF消息到server,暂停向该client更新消息。直到CA_PROTO_EVENTS_ON再次发送,恢复数据更新。

    应用层调用

    连接管理

    epics通过ca_create_channel()来创建通信的信道,包含创建的pv名,以及可选的回调函数。如果callback指针为空,那么需要不停的poll或者pend来等待执行结果。通常建议搭配connectionHandler,当有连接变化的时候,主动触发回调函数执行。在创建channel的过程中,会伴随信道的创建过程。

    上下文资源

    ca_context_create()用来创建channel所需要的上下文。包含get/put/monitor的回调函数、线程资源、socket以及其他需要的资源。ca_context_create()实际是有一个参数的,表示回调函数是否可以抢占式调用。对于抢占式调用,特别需要注意资源的保护,避免其他线程同时操作同一数据结构。另外,ca_client_context资源的分配需要在任何实际ca操作之前,如果没有,默认会创建非抢占式的context。

    线程管理

    在单线程模式下,所有的channel会共用同一个context,资源能够最大化利用,但对于程序的执行效率会有影响。在多线程模式下,一般而言,每个channel都会创建自己的context。这种方式能更好的更简单的执行,每个线程完成独立的工作即可,但是会存在一定的资源浪费。因此,推荐使用一个context,其他线程附加到创建context的线程上。需要注意的是,这些线程必须是抢占式的,而独占式回调更适合单线程或者需要等待完成的任务。

    相关文章

      网友评论

        本文标题:CA工作机制

        本文链接:https://www.haomeiwen.com/subject/vakiwktx.html