参考文献:
1. 官方CA协议说明 https://epics.anl.gov/base/R3-16/1-docs/CAproto/index.html#_operation(本翻译的原文)
整体服务器操作
CA服务器将至少维护两个套接字。
一个套接字是绑定到CA端口的UDP套接字(def.5064,数据端口),该套接字必须监听PV名称搜索请求的广播。 PV名称搜索响应作为单播消息发回给广播源。 这个套接字或另一个UDP套接字应该定期将信标发送到CA Beacon端口(def.5065)。
TCP套接字侦听任意端口。 PV名称搜索响应中包含确切的端口号。 该套接字将用于构建虚拟电路。
CA服务器不应该响应自己的PV名称搜索请求,除非来自同一客户端的该PV的CA——PROTO——CREATE——CHAN可以被成功预期。 否则,在严格的重试循环中会产生过大的负载。
【备注:我觉得在此有必要说一下什么是服务器信标,以及5064和5065端口。】
服务器信标是由服务器发出的UDP包,以示它们还存在。该信标自初始化起就开始连续发送,发送间隔从初始值逐渐增加至最大间隔值,然后一直以最大间隔持续发送信标。服务器以一定间隔持续发送信标,就好比人的心跳。发送这个信标的端口为5065端口(就把它记作心跳端口吧)。服务器信标由客户端接收。服务器信标还可用于恢复断开的虚拟电路连接。
另外,这里提一句,用于接收/发送数据的端口为5064端口(就把它记作数据端口吧)。不管是响应CA客户端的名称搜索请求时(UDP),还是建立TCP连接后开始传输数据时,都是使用这个数据端口。
整体客户端操作
CA客户端应该在本地系统上使用Repeater维护注册服务,并且在必要时启动(或重启)它。
客户端将发送PV名称搜索消息并监听回复。 通常,为了避免重复搜索,并且处理服务器响应,客户端将维护一个未应答的名称搜索表和最近搜索结果的缓存表。
一旦收到肯定的搜索答复,就会在需要的情况下打开响应服务器的虚拟电路。 如果客户端已经有一个对该服务器开放的电路,则该电路就会被重用。 当电路可用时,会在其上创建一个通道,然后会在该通道上执行各种get / put / monitor操作。
名称搜索
找到向特定客户端发送PV数据的服务器 的过程可以通过UDP协议执行。在4.12及以上版本的CA协议也可以通过TCP连接执行。
在任何一种情况下,每个客户端都应该预先配置一组目标搜索地址来发送查询。 对于UDP搜索,这是单播或广播端点(IP和端口)的列表。 对于TCP搜索,这是端点的列表。
建议使用 除环回外的所有网络接口的广播地址 作为默认的UDP端点列表。
建议在客户端启动时,将电路建立到TCP搜索列表中的所有端点。
搜索结果是暂时的。 随后的搜索可能产生不同的结果。 因此,除非活动频道已经打开,否则应该重新尝试查询。
UDP搜索数据包
在一个UDP数据包中可能包括了几个CA消息。
包含CA_PROTO_SEARCH信息的数据报文必须以CA_PROTO_VERSION信息开头。
数据包的大小限制了一个数据包中包含的搜索请求的数量。为了提高效率,建议在每个数据包中包含尽可能多的搜索请求(但要受数据报大小的限制)。
CA服务器不得发送CA_PROTO_NOT_FOUND作为UDP搜索请求的响应。
TCP搜索
除非已接收CA_PROTO_VERSION消息并显示CA协议为4.12及以上版本,否则不得在电路上发送CA_PROTO_SEARCH消息。
如果支持,CA_PROTO_SEARCH消息可能在电路打开情况下的任何时候被发送。
如果DO_REPLY位被设置了,那么CA服务器可能发送CA_PROTO_NOT_FOUND作为对UDP搜索请求的响应。
客户的可能忽略CA_PROTO_NOT_FOUND消息。
CA_PROTO_NOT_FOUND消息不是最终结果,后续搜索可能会产生不同的结果。
虚拟电路
不活动超时
电路被创建后,客户端和服务器都必须开始倒计时定时器。 只要电路上接收到任何事件(包括CA_PROTO_ECHO消息),该定时器就被重置为其初始值。 如果定时器达到零,则电路关闭。
客户端必须在服务器的倒计时到零之前给它发送CA_PROTO_ECHO消息。 建议客户端在倒计时计数达到初始值的一半时给服务器发送消息。
当服务器收到CA_PROTO_ECHO消息时,必须立即将其复制并发回给客户端。
服务器的倒计时定时器的推荐初始值为30秒。
电路设置
电路被创建后,客户端和服务器必须发送CA_PROTO_VERSION作为他们互相发送的第一条消息,并且 该消息应该立即发送。
实施者注意事项。 对于版本3.14.12之前的EPICS Base,由于缓存问题,RSRV不会立即发送版本消息。具体来说,就是在其他某些响应强制刷新发送队列之前,不会发送版本消息。
此外,客户端应该发送CA_PROTO_HOST_NAME和CA_PROTO_CLIENT_NAME消息。 完成此操作后,电路就可以创建通道了。
请注意,在创建第一个通道后,不应(重新)发送主机和客户端名称消息。 如果客户端或主机名字符串发生变化,则应该关闭电路。
如果没有收到主机或客户端名称消息,服务器必须认为客户端是匿名的。 建议匿名用户不被授予Put操作的权限。
通道创建
通过客户端的CA_PROTO_CREATE_CHAN请求开始创建通道。此请求消息包括PV名称字符串和客户端标识CID。
如果服务器无法提供客户端指定的PV,则使用相同的CID回复CA_PROTO_CREATE_CH_FAIL。服务器一定不能记住通道创建请求失败的CID,因为客户端可能会立即重新使用它们。
若服务器可以提供客户端指定的PV,则它将先回复CA_PROTO_ACCESS_RIGHTS,然后回复CA_PROTO_CREATE_CHAN。接着可能遵循进一步的CA_PROTO_ACCESS_RIGHTS消息以反映对访问权限的更改。
请注意,CA_PROTO_CREATE_CHAN回复包括通道的本机DBR数据类型以及可由get,put或monitor操作检索/设置的最大元素数。这些属性在通道的生命周期内是固定的。
回复还包含服务器选择标识符SID。SID与CID这两个标识符一起,将用于在后续操作中调用通道。
在客户端发送CA_PROTO_CLEAR_CHANNEL请求并收到其回复之前,在客户端收到CA_PROTO_SERVER_DISCONN消息或(TCP连接时)电路被关闭前,通道都保持活动状态。
在服务器发送CA_PROTO_CLEAR_CHANNEL回复或CA_PROTO_SERVER_DISCONN消息后,它可以立即重用SID。
在客户端收到CA_PROTO_CLEAR_CHANNEL回复或CA_PROTO_SERVER_DISCONN消息后,它可以立即重用CID。
因此,在客户端发送CA_PROTO_CLEAR_CHANNEL请求或服务器发送CA_PROTO_SERVER_DISCONN请求后,不应该再为已关闭的通道发送其他消息(包括CA_PROTO_ERROR)。
PUT操作
将数据写入通道的操作以CA_PROTO_WRITE或CA_PROTO_WRITE_NOTIFY请求开始。两者之间的区别在于,当操作成功后,CA_PROTO_WRITE_NOTIFY给出操作成功的答复,而CA_PROTO_WRITE没有。
在并不要求所有Put操作都被执行的情况下,应该使用CA_PROTO_WRITE。服务器应该尽最大努力确保在收到一串CA_PROTO_WRITE请求后,(这些请求的)后一个请求能被处理(其他请求可能被丢弃,这里指的其他请求应该是指接收那一连串请求期间的其他请求)。
CA_PROTO_WRITE_NOTIFY请求意味着客户端要等到这个请求被执行完成后再继续(接收了服务器发回的操作成功消息就表示执行完成,因此这句的意思应该是:客户端要等当前请求被成功执行后再继续后面的操作)。服务器必须回复所有CA_PROTO_WRITE_NOTIFY请求。服务器应该尽最大努力来完全处理所有CA_PROTO_WRITE_NOTIFY请求。
两个请求消息都包括SID以确定正在操作哪个通道。
此外,还包括客户端标识IOID。此标识符将存在于CA_PROTO_WRITE_NOTIFY回复中,以及由Put请求产生的任何CA_PROTO_ERROR异常消息。
GET操作
使用CA_PROTO_READ_NOTIFY请求查询通道的当前值。
服务器必须回复所有CA_PROTO_READ_NOTIFY请求。 服务器应该尽最大努力来完全处理所有CA_PROTO_READ_NOTIFY请求。
CA_PROTO_READ_NOTIFY消息包括了 用于确定正在操作哪个通道的SID标识符 和 在回复中也要包括的标识符IOID。
IOID必须在通道上是唯一的。
Mornitor操作
Monitor操作是持久订阅的,它由CA_PROTO_EVENT_ADD请求启动,并以CA_PROTO_EVENT_CANCEL请求终止。
CA_PROTO_EVENT_ADD和CA_PROTO_EVENT_CANCEL消息都包括通道标识SID以及客户端标识SubscriptionID。
SubscriptionID必须在通道上是唯一的。
订阅被创建后,若(订阅通道的)值是存在的,则服务器应该立即发送包含通道当前值的CA_PROTO_EVENT_ADD回复。
服务器在收到CA_PROTO_EVENT_CANCEL请求后,必须发送一个零有效负载大小的最终CA_PROTO_EVENT_ADD应答。 服务器在收到CA_PROTO_EVENT_CANCEL请求之前,不得发送具有零有效负载大小的CA_PROTO_EVENT_ADD应答。
Errors
任何客户端消息都可能导致服务器回复CA_PROTO_ERROR消息。
GET和Monitor操作中的数据计数
在4.13版本之前的CA协议中,CA_PROTO_EVENT_ADD回复或CA_PROTO_READ_NOTIFY回复中的元素计数必须与相应的CA_PROTO_EVENT_ADD请求或CA_PROTO_READ_NOTIFY请求中给出的相同。一个包含零个元素的请求必定导致ECA_BADCOUNT异常。如果服务器无法提供所请求的所有元素,则它会使用空字节填充消息正文。
从4.13版本开始的CA协议中,对零个元素的请求有效。然后,回复中的元素计数是服务器可以提供的元素数量(可能为零)。
回复中的元素计数不得超过通道上的最大元素数。
如果CA_PROTO_EVENT_ADD回复中的字节数为零,则此动态数组大小功能会在协议中产生潜在的歧义。
因此,建议客户端不要为普通DBR_ *类型创建动态监听器。建议需要创建此类监听器的客户端将类型提升为相应的DBR_STS_ *(内部处理可以忽略额外的元数据)。然后零元素计数具有非零尺寸的正文。
实施者请注意。 RSRV将始终在CA_PROTO_EVENT_ADD回复中提供至少一个元素。在收到CA_PROTO_EVENT_CANCEL请求之前,libca将默认忽略大小为零的CA_PROTO_EVENT_ADD回复。