目录
1. TIPC FUNDAMENTALS ????????????1.1. CLUSTER ????????????1.2. ADDRESSING ????????????1.3. MESSAGING ????????????1.4. SERVICE TRACKING 2. SOCKET API ????????????2.1. STRUCTURES ????????????2.2. ROUTINES ????????????2.3. EXAMPLES 3. LIBTIPC C API ????????????3.1. ADDRESSING ????????????3.2. EXAMPLES 4. GO API 5. PYTHON API 6. JAVA API 7. TIPS AND TECHNIQUES ????????????5.1. DETERMINING OWN NODE ????????????5.2. CHANGING SOCKET RECEIVE BUFFER ????????????5.3. WHEN TO USE IMPLIED CONNECT ????????????5.4. PROCESSING A RETURNED MESSAGE
引言
本文档旨在帮助软件开发人员编写使用TIPC的应用程序。有关TIPC协议的介绍性信息、其主要概念以及设置和操作节点和集群的说明,请访问项目网站:http://www.tipc.io.为了从本文中获益,读者还应该至少具备计算机网络的基本知识,并熟悉socket编程。
应该注意的是,TIPC在Linux 3.10(现在被取代的TIPC 2.0文档中提到的版本)和Linux 5.8(本文档所基于的版本)之间经历了重大的功能更改和升级。
这些变化中最重要的是:
- 一个新的、基于工作队列的拓扑服务器。(由薛颖在Linux 3.10中介绍。)
- 一个新的管理工具,tipc,淘汰了旧的tipc配置。(Richard Alpe,Linux 3.18)
- 介绍内核名称空间支持。(薛颖,Linux 3.19)
- 能够通过UDP/IPv4或UDP/IPv6承载传输TIPC。(Erik Hugne,Linux 4.0)
- 一种更健壮、性能更好、可扩展的多播服务。(Jon Maloy,Linux 4.3)
- 能够使用重叠环监控算法扩展到数百个节点。(Jon Maloy,Linux 4.7)
- 通过通信组功能引入消息总线服务。(Jon Maloy,Linux 4.14)
- 废除了区域概念,但无论如何都没有实施。(Jon Maloy,Linux 4.17)
- 引入了一个扁平的128位节点标识,取代了以前的结构化32位节点地址。(Jon Maloy,Linux 4.17)
- 使节点标识自动配置。(Jon Maloy,Linux 4.17)
- 更改了用户API中的术语,从端口名更改为服务地址,从端口名序列更改为服务范围,从端口标识更改为套接字地址。(Jon Maloy,Linux 4.17)
- 增加了广泛的跟踪支持。(Tonong Lien,Linux 4.20)
- 引入了一种“智能唠叨(Smart Nagle)”机制,可根据流量特性自动开关。对于较小的消息流量,这将使流套接字吞吐量加倍。(Jon Maloy,Linux 5.4)
- 为所有节点间通信添加了内置的基于AEAD的加密和身份验证协议(Tuong Lien,Linux 5.4)。RHEL-8还没有。
- 一种“虫洞”内部名称空间机制,使消息可以绕过位于同一主机上的容器之间的任何网络接口,在其中抄近路。这使容器间通信具有与正常节点内通信相同的性能(并且比TCP好得多)。(Hoang Le,Linux 5.4)
- 介绍了一种基于雷诺算法的可变窗口链路流量控制算法。使最大链路吞吐量提高25%。(Jon Maloy/Xin Long,Linux 5.5)
- 在网络基础设施允许的情况下,根据真实的网络广播进行绑定表更新,通常本质上是广播的。(Hoang Le,Linux 5.8)尚未在RHEL-8中使用。
在同一时期,为了提高TIPC代码的可读性、可维护性、健壮性和性能,人们做出了巨大的努力。数据结构得到了简化和分离,锁定策略得到了很大改进,代码符合常见的Linux编码风格指南。 应该强调的是,通过所有这些更改,在协议和用户API方面都非常小心地保持了与TIPC早期版本的向后兼容。
1.?TIPC基础
以下各节简要概述了TIPC中使用的主要概念。
1.1.?集群
TIPC网络由单独的处理元件或节点组成。这些节点根据其指定的簇标识被排列成簇。所有具有相同集群身份的节点将彼此建立链接,前提是网络的设置允许它们之间的相互邻居发现。只有当不同集群中的节点可能会发现彼此时(例如,如果它们连接到同一子网),才有必要更改集群标识的默认值。不同集群中的节点无法使用TIPC相互通信。
每个节点都有一个128位的节点标识,该标识在节点集群中必须是唯一的。如果该节点将是集群的一部分,则用户可以依赖该节点的自动配置功能,其中在连接第一承载时生成标识,或者他可以显式地设置标识,例如,根据节点的主机名或UUID。如果一个节点不是集群的一部分,那么它的标识可以保持为默认值零。
每个节点还由一个32位哈希数唯一标识。该编号由节点标识生成,并在协议内部用作节点地址。邻居发现协议的扩展可以保证其值在集群中是唯一的。这个数字对协议性能和向后兼容性都有帮助。
1.2.?寻址
TIPC套接字API提供三种不同的地址类型:
- Service Address. 此地址类型由32位服务类型标识符和32位服务实例标识符组成。类型标识符通常由用户应用程序程序员确定和硬编码,但其值可能必须与同一集群中可能存在的其他应用程序协调。实例标识符通常由程序根据特定于应用程序的标准进行计算。
- Service Range. 此地址类型表示同一类型的服务地址范围,实例的范围在下限和上限之间。通过将套接字绑定到此地址类型,可以使其表示许多实例,这在许多情况下都是有用的。此地址类型也用作多播地址,稍后将对其进行更详细的解释。
- Socket Address. 此地址是群集中特定套接字的引用。它包含一个32位端口号和一个32位节点哈希号。端口号是在创建套接字时由系统生成的,节点哈希是根据前面解释的相应节点标识生成的。这种类型的地址可用于连接或发送消息,使用方式与服务地址相同,但只有在引用的套接字存在时才有效。
将套接字绑定到服务地址或地址范围时,必须指明绑定的可见性范围。有两个选项,TIPC_NODE_SCOPE(如果用户只想要节点本地可见性),TIPC_CLUSTER_SCOPE(如果用户想要集群全局可见性)。套接字如何绑定到服务地址几乎没有限制:一个套接字可以绑定到多个地址或范围,许多套接字可以绑定到同一地址或范围。但是,服务类型0到63保留供系统内部使用,不适用于用户空间应用程序。
当通过服务地址发送消息时,发送方可能会指示查找范围,也称为查找域。这是一个节点散列号,将符合条件的目标套接字集限制为指定的节点。如果该值为零,则从源节点可见的整个集群中的所有匹配套接字都是合格的。
1.3.?消息传递
TIPC信息传输可以以不同的方式执行。
1.3.1.?数据报消息
数据报消息是长度在1到66000字节之间的离散数据单元,在SOCK_DGRAM或SOCK_RDM类型的未连接套接字之间传输。与UDP数据包一样,TIPC数据包也不能保证到达目的地,但它们被发送的可能性仍然比前者大得多。由于链路层传输保证,数据报传输的唯一限制因素是套接字接收缓冲区大小。发送方也可以通过给套接字一个适当的传递优先级来增加成功的机会。有四个这样的优先级别。默认值为TIPC_LOW_IMPORTANCE,但可以通过套接字选项TIPC_IMPORTANCE进行更改。
此外,当接收缓冲区溢出时,发送者可以选择是否只是希望丢弃他的消息,或者是否应该接收到关于未能发送的指示。在后一种情况下,原始消息的一个可能被截断的(前1024字节)副本连同错误代码TIPC_ERR_重载一起返回给发送方。这种机制也适用于其他类型的传递失败,因此用户甚至可能会遇到错误代码TIPC_ERR_NO_NODE和TIPC_ERR_NO_PORT。发送方从套接字读取错误代码并返回字节作为辅助数据。此属性的默认设置为关闭,但可以通过套接字选项TIPC_DEST_DROPPABLE启用。
数据报消息可以通过套接字地址、服务地址或多播地址发送。
- 如果指示了套接字地址,则消息将传输到该套接字。
- 当使用服务地址时,可能存在多个匹配目的地,并且传输方法成为通常被表示为选播的方法,即,可以选择任何匹配目的地。在这种情况下,将服务地址转换为套接字地址的函数使用循环算法来降低目的地之间的负载偏差风险。然而,应该注意的是,该算法是节点全局的,因此除非发送者单独在节点上使用该地址,否则他不能保证其特定消息将均匀地分布在目的地之间。
- 地址类型服务范围也可以作为多播地址翻倍。当应用程序将服务范围指定为目标地址时,它确实会有效地指示TIPC向群集中所有匹配的套接字发送消息副本。任何绑定到指定的多播范围内的一个或多个实例的套接字都将只接收消息的一个副本,而不会更多。多播数据报消息与单播/选播消息在一个方面也不同,-查找范围始终是群集全局的,不能更改。
通过从默认值增加接收缓冲区大小,可以降低消息拒绝的风险。
通过服务地址发送的数据报消息可能受到另一种机制的约束,该机制旨在降低传递失败的风险。由于绑定表更新的无事务性和非原子性,消息的主地址查找可能会在源节点上成功,而目标套接字在到达目标节点时已消失。在这种情况下,会尝试在目标节点上进行二级服务查找,只有当查找失败时,才会将消息丢弃或返回给发送方。
当在套接字中接收到数据报时,接收方可以从recvmsg()控制块中读取源套接字地址,正如人们所期望的那样。此外,还可以读出发件人使用的服务地址(如果有的话)。在某些情况下,此功能可能很方便。
由于缺乏数据报消息的传递保证,只有当程序员确信没有接收缓冲区溢出的风险,或者他能够处理后果时,才应该使用这种传输方法。如果他需要一个更健壮的机制,端到端流控制,他应该考虑使用群组消息。
1.3.2.?面向连接的消息传递
可以建立和使用连接,就像我们习惯于使用TCP一样:服务器创建一个SOCK_流套接字并调用accept();客户端创建同一类型的阻塞或非阻塞套接字,并在其上执行connect(),然后开始发送或接收。使用的地址类型可以是服务地址或套接字地址(客户端),或服务地址或服务范围(服务器端)。
然而,TIPC确实提供了两种不同的场景,在某些情况下可能有用。
- 首先,可以将套接字创建为SOCK_SEQPACKET,而不是SOCK_STREAM类型,这意味着数据交换必须以最大66000字节的消息为单位进行。
- 其次,客户端可以通过简单地向accept()套接字发送数据消息来初始化连接。同样,生成的服务器套接字可以向客户端返回数据消息以完成连接。通过这种方式,TIPC提供了一种隐含的,也称为0-RTT连接设置机制,在许多情况下特别节省时间。
TIPC连接最显著的特性仍然是,它们能够在失去与对等socket的接触时迅速做出反应,而无需依靠邻居的主动心脏跳动。
- 当用户或进程崩溃导致套接字无法正常关闭时,内核套接字代码将主动向对等方发出FIN消息。
- 当与群集节点的联系丢失时,本地链路层将向所有与该节点有连接的套接字发出FIN消息。对等节点故障发现时间可配置为50毫秒,而默认值为1500毫秒。
- 为了处理一个不太可能完成的悬空连接,每个套接字端点都会维护一个1小时的时间段计时器,以探测对等方在过去一段时间内是否保持沉默。如果在下一个超时过期时没有响应,连接将中止。
1.3.3.?Group Messaging
如上所述,组消息传递可以简单地描述为数据报消息传递,但具有端到端的流控制,因此具有传递保证。然而,还有一些显著的差异需要进一步描述。
- 消息传递只能在一组封闭的成员套接字中完成。
- socket通过调用socket选项TIPC_GROUP_JOIN?并将struct tipc_group_req*作为参数来连接组。此结构的一部分是服务地址,其中类型字段表示组标识,实例字段表示成员标识。因此,一个成员只能绑定到一个服务地址,仅此而已。
- 发送选播消息时,查找算法应用常规循环算法。然而,在做出选择之前,它还考虑潜在接收器上的当前负载,即广告发送窗口。
- 与常规数据报多播一样,组多播是通过将服务范围指示为目的地来执行的。然而,在组多播中,在查找过程中只考虑范围的较低值。这意味着,只有那些以该实例值加入组的成员才会收到已发送多播消息的副本。
- 还有一种群组广播模式,它向所有群组成员发送消息,而不考虑其成员身份。发送方使用send()原语表示其广播意图。
- 有一个专门的协调滑动窗口协议来处理“流量紧缩”,即许多成员可能试图同时向同一目的地发送流量的情况。这意味着,即使在这种极端情况下,交付担保也有效。
- 接收消息时,接收方使用recvmsg(),并可以从附带的结构msghdr中读取发送方的源地址、套接字地址和绑定服务地址。
- 除了消息传递保证之外,还有顺序性保证。这种保证甚至在消息传递模式之间有效,例如,成员可以以任何顺序发送单播、选播、多播或广播,并且保证在任何特定接收者中以相同的顺序接收消息。
- 当加入一个组时,一个成员可能会表明它是否有资格获得他自己发送的任意广播/多播/广播消息的环回副本。默认情况下,此设置处于禁用状态。
- 当加入一个组时,一个成员可能会指出它是否希望接收该组其他成员的加入或离开活动。此功能利用服务跟踪功能,但与其他用户相反,组成员将在成员套接字中接收事件。因此,发行顺序性担保成为可能;-加入事件总是在新成员的第一条消息之前到达,-离开事件总是在离开成员的最后一条消息之后传递。一个事件就是接收一条空的带外消息,并附上新成员的两个源地址。I此外,离开事件消息设置了EOR位。事件订阅设置的默认值为off。
- 消息组具有可扩展性和性能,但这在多大程度上取决于它们在节点之间的分布和流量模式。在具有全流量爆炸的单个节点上,建立一个拥有64个成员的组没有问题,而如果该组是分布式的,则可以有更多成员。如果发送方的最佳性能很重要,建议不要让它在单播/选播和多播/广播之间切换太频繁。
1.4.?Service Tracking(服务跟踪)
TIPC提供服务跟踪功能,使应用程序能够跟踪群集中服务地址和服务范围的可用性。
1.4.1.?Service Subscription(服务订阅)
应用程序通过使用服务地址{TIPC_TOP_SRV,TIPC_TOP_SRV}打开到TIPC内部拓扑服务的SOCK_SEQPACKET类型连接来访问拓扑服务。然后,它可以向拓扑服务发送一个或多个服务订阅消息,指示要跟踪的服务地址或范围。作为回报,只要集群中的套接字绑定或解除绑定匹配的地址,拓扑服务就会将服务事件消息发送回应用程序。允许一个应用程序使用同一连接同时激活多个订阅。
应用程序和拓扑服务之间的消息交换是完全异步的。应用程序可以随时发出新的订阅请求,而拓扑服务可以随时向应用程序发送有关匹配绑定的事件消息。
应用程序和拓扑服务之间的连接将继续,直到应用程序终止连接,或者直到拓扑服务遇到要求其终止连接的错误。当连接结束时,无论出于何种原因,TIPC都会自动取消所有相关订阅。
尽管服务订阅通常指向节点本地拓扑服务器,但也完全可以建立到其他节点服务器的连接。如果需要在远程节点上订阅节点本地绑定,这可能很有用。需要注意的是,在这种情况下,不需要按网络字节顺序发布订阅,-接收拓扑服务器将检测使用的表示并相应地响应它。
1.4.2. 群集拓扑订阅
当TIPC与另一个节点建立联系时,它会在绑定表中内部创建一个绑定{type=TIPC_NODE_STATE,instance=peer node hash number}。这使得节点上的应用程序可以随时跟踪可访问的对等节点。
1.4.3. 群集连接订阅
当TIPC建立到另一个节点的新链接时,它会在绑定表中内部创建一个绑定{type=TIPC_link_STATE,instance=peer node hash number}。这使得节点上的应用程序可以随时跟踪到对等节点的工作链接。这种类型的绑定不同于上面描述的拓扑订阅绑定,因为可能有两个链接,因此也有两个绑定来跟踪每个对等节点。尽管此绑定类型仅在节点可见性的情况下发布,但如上所述,可以将其与远程节点拓扑订阅相结合,以获得集群中连接的完整且连续的矩阵视图。
2.?SOCKET API
程序员可以使用BSD套接字API访问TIPC的功能。它支持程序员从其他基于套接字的协议中了解的通用套接字API,但在TIPC的上下文中,一些例程给出了必须理解的特定解释。本节概述了这些差异。
2.1.?TIPC特定结构
socket API的TIPC特定部分在/usr/include/linux/tipc.h中定义。在大多数Linux发行版中。也可以在这里研究。定义了以下结构:
2.1.1.?Address Types
struct tipc_socket_addr { struct tipc_service_addr { struct tipc_service_range {
__u32 ref; __u32 type; __u32 type;
__u32 node; __u32 instance; __u32 lower;
}; }; __u32 upper;
};
struct sockaddr_tipc {
unsigned short family;
unsigned char addrtype;
signed char scope;
union {
struct tipc_socket_addr id;
struct tipc_service_range nameseq;
struct {
struct tipc_service_addr name;
__u32 domain;
} name;
} addr;
};
前三种地址类型的含义在“寻址”下描述。最后一个, struct sockaddr_tipc在与本地套接字交互时使用,填写如下:
- family?must always be?AF_TIPC.
- addrtype?is one of?TIPC_SOCKET_ADDR, TIPC_SERVICE_ADDR, TIPC_SERVICE_RANGE?or
TIPC_ADDR_MCAST. The latter value is used when sending multicast messages, and indicates a service range. - scope?is one of?TIPC_CLUSTER_SCOPE?or?TIPC_NODE_SCOPE, and is only used during binding.
- domain?indicates a lookup scope during sending, and contains either a valid node hash number or zero.
2.1.2.?服务跟踪定义
struct tipc_subscr { struct tipc_event {
struct tipc_service_range seq; __u32 event;
__u32 timeout; __u32 found_lower;
__u32 filter; __u32 found_upper;
char usr_handle[8]; struct tipc_socket_addr port;
}; struct tipc_subscr s;
};
一旦与拓扑服务建立了连接,应用程序就可以逐个向其发送struct tipc_subscr的实例。其字段必须填写如下:
- seq:服务地址或兴趣范围。如果只跟踪一个服务地址,则上下字段设置为相等。
- timeout(超时):以毫秒为单位指定订阅的生存时间的值。如果此字段设置为TIPC_WAIT_FOREVER,订阅将永远不会过期。
- filter:一个位字段,指定拓扑服务应如何对订阅进行操作。可以指定三种可能的操作:
-TIPC_SUB_SERVICE:订阅者只需要“边缘”事件,即当遇到第一个匹配绑定时需要一个TIPC_PUBLISHED?的事件,当从绑定表中删除最后一个匹配绑定时需要一个TIPC_WITHDRAWN?的事件。因此,此事件类型仅通知集群中当前是否存在任何匹配绑定。
-?TIPC_SUB_PORTS:?订阅者希望绑定表的每次匹配更新都有一个事件。通过这种方式,它可以跟踪集群中存在的每个单独的匹配服务绑定。
-?TIPC_SUB_CANCEL:?订阅者不希望此服务范围再发生任何事件,即取消订阅。除“取消”位外,此订阅必须是原始订阅请求的副本。
- usr_handle:?一个64位字段,由订阅者自行设置和使用。
发送订阅后,订阅服务器将收到零条或多条包含struct tipc_事件的消息,其中包含以下信息:
-?TIPC_PUBLISHED:?在绑定表中找到了匹配的绑定。如果在发布订阅时表中有匹配项,则会出现事件筛选器中指定的一个或所有匹配项的事件。此后,每次变更都会有一个事件,这也取决于指定的内容。 -?TIPC_WITHDRAWN:?已从绑定表中删除匹配的绑定。此事件类型还遵循事件筛选器中指定的规则。 -?TIPC_SUBSCR_TIMEOUT:?根据给定的超时值指定,订阅已过期,已被删除。
- found_lower/found_upper:?描述匹配绑定的范围。此范围不一定与订阅的范围相同,因为两者之间的任何重叠都被视为匹配并触发事件。
- port:?匹配套接字的套接字地址。
- s:原始订阅请求的准确副本。
2.1.3.?Socket Control Structures
struct tipc_group_req {
__u32 type;
__u32 instance;
__u32 scope;
__u32 flags;
};
struct tipc_group_req在setsockopt()中传递,以加入通信组并在getsockopt()在加入后读取自己的成员身份设置。其字段的用法如下:
- type:?The group identity.
- instance:?The member identity.
- scope:?Visibility scope.?TIPC_CLUSTER_SCOPE?or?TIPC_NODE_SCOPE.
- flags:?Bit field with member properties:?TIPC_GROUP_LOOPBACK?and/or?TIPC_GROUP_MEMBER_EVTS.
struct tipc_sioc_nodeid_req { struct tipc_sioc_ln_req {
__u32 peer; __u32 peer;
char node_id[TIPC_NODEID_LEN]; __u32 bearer_id;
}; char linkname[TIPC_MAX_LINK_NAME];
};
- struct tipc_sioc_nodeid_req与ioctl()一起用于检索节点标识,给定一个节点哈希数作为密钥。
- ?struct tipc_sioc_ln_req与ioctl()一起用于检索链接名,给定对等节点哈希号和作为密钥的承载身份。散列号从tipc_event::port::node获得,承载身份从接收到的群集连接事件中的tipc_event::port::ref的最低16位获得。(上面的16位包含对等端点的承载身份,并使第三方能够关联这两个端点。)群集连接性订阅是一个使用{TIPC_LINK_STATE,0,0xffffffff}服务范围订购的订阅。
?
2.2.?Routines
TIPC支持以下套接字API例程:
- int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
接受套接字上的新连接。如果非空,则cliaddr设置为对等套接字的套接字地址。
- int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
将服务地址或范围绑定或解除绑定到套接字。可见性范围设置为TIPC_NODE_SCOPE?或TIPC_CLUSTER_SCOPE。通过使用最初使用的作用域的算术倒数,或通过将addrlen设置为零来执行解除绑定操作。请注意,使用范围0(零)是合法的,其含义是TIPC_CLUSTER_SCOPE,但此类绑定不能单独解除绑定。还要注意,bind()可以在同一个套接字上多次调用。
关闭socket。如果套接字未连接,则根据其“可丢弃”位拒绝(即丢弃或返回)接收队列中剩余的未处理消息。
- int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
将socket?连接到对等设备。虽然这是使用TIPC更有效的双向握手机制,但它表面上看起来确实与TCP连接设置完全相同。如果使用了服务地址,查找将遵循与数据报消息相同的规则。同时支持阻塞和非阻塞设置。
- int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen)
获取对等套接字的套接字地址。此调用仅为s连接的套接字定义。
- int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen)
获取套接字的套接字地址。注意,这个调用对于获取自己节点的散列号也很有用,因为这是获取的地址的一部分。
- int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen)
获取套接字选项的当前值。SOL_TIPC级别支持以下optname值:?
TIPC_IMPORTANCE:?See setsockopt() below. TIPC_DEST_DROPPABLE:?See setsockopt() below. TIPC_CONN_TIMEOUT:?See setsockopt() below. TIPC_SOCK_RECVQ_DEPTH:?返回套接字接收队列中的消息数。 TIPC_GROUP_JOIN:?返回带有组成员身份和设置的结构tipc_group_req*。
- int ioctl(int fd, unsigned long request, ...)
有两个ioctl()调用:
1)?SIOCGETLINKNAME:?? 将带有节点散列号和承载身份的结构tipc_sioc_ln_req*作为密钥,并返回链接名。 2)?SIOCGETNODEID:?以节点散列号为键的struct tipc_sioc_node_req*并返回节点标识。
- int listen(int sockfd, int backlog)
使套接字能够侦听连接请求。backlog参数被忽略。
- int poll(struct pollfd *fdarray, unsigned long nfds, int timeout)
使用标准poll()机制指示指定的TIPC套接字已准备好进行I/O操作。返回的事件标志设置如下:
POLLRDNORM?and?POLLIN?如果套接字的接收队列为非空,则设置。 POLLOUT? 如果套接字未处于传输拥塞状态,即尝试通过拥塞的链路或向拥塞的对等方发送时未被阻止,则设置轮询。 如果套接字的连接已终止,则设置POLLHUP。请注意,select()和epoll_create()/epoll_ctl()/epoll_wait()也是根据同样的规则支持。
- ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags)
尝试从套接字接收消息。 请注意,返回值0在TIPC中有特殊含义,具体取决于socket?类型:
-对于数据报套接字,它表示返回的未送达数据消息,该消息包含1024个前字节 现在可以作为辅助数据读取。
-对于已连接的套接字,它表示对等套接字正常关闭;否则返回-1。
-对于组套接字,它表示接收了成员资格事件(如果适用)。
应用程序可以通过使用recvmsg()而不是recv()来确定连接终止和/或消息未传递的确切原因。接收期间支持MSG_PEEK、MSG_WAITALL和MSG_DONTWAIT标志;忽略所有其他标志。
- ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,struct sockaddr *from, socklen_t *addrlen):
尝试从套接字接收消息。如果成功,则在from参数中返回消息发送者的套接字地址。另请参见recv()例程的注释。
- ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
尝试从套接字接收消息。如果成功,消息发送者的套接字地址将被捕获到消息的msg_name字段中(如果非空),与消息相关的辅助数据将被捕获到消息的msg_control字段中(如果非空)。
可以捕获以下辅助数据对象: TIPC_ERRINFO:?与返回数据消息或连接终止消息关联的TIPC错误代码,以及返回数据的长度。(8字节:错误代码+数据长度) TIPC_RETDATA:?返回数据消息的内容,最多1024字节。 TIPC_DESTNAME:?The service address or range that was specified by the sender of the message (12 bytes).
如果请求辅助数据对象捕获(即msg->msg_control为非空),但提供的空间不足,则会设置MSG_CTRUNC?标志以指示未捕获一个或多个可用对象。
- int select(int maxfdp1, fd_set *readset, fd_set *writeset,fd_set *exceptset, const struct timevale *timeout)
使用标准select()机制指示指定的TIPC套接字已准备好进行I/O操作。请参阅poll()的条目。
- ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags)
此例程有两个用途: 1) 尝试将消息从连接的套接字发送到对等套接字。 2) 尝试从组成员套接字发送组广播。 在案例1)中,仅支持MSG_DONTWAIT标志。
- ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags)
Attempt to send a message from the socket to the specified destination. There are three cases: 1) If the destination is a socket address the message is unicast to that specific socket. 2) If the destination is a service address, it is an anycast to any matching destination. 3) If the destination is a service range, the message is a multicast to all matching sockets. ??? Note however that the rules for what is a match differ between datagram and group messaging. ? - ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
???????????????const struct sockaddr *to, socklen_t addrlen) Attempts to send a message from the socket to the specified destination. See comments under?sendmsg(). ? - int setsockopt(int sockfd, int level, int optname, const void *optval,
?????????????? socklen_t optlen) Set a socket option. The following?optname?values are supported at level SOL_TIPC: TIPC_IMPORTANCE:?This option governs how likely a message sent by the socket is to be affected by ?????? congestion. A message with higher importance is less likely to be delayed due to link congestion ?????? and less likely to be rejected due to receiver congestion. The following values are defined: ?? TIPC_LOW_IMPORTANCE, TIPC_MEDIUM_IMPORTANCE, TIPC_HIGH_IMPORTANCE,?and ???????TIPC_CRITICAL_IMPORTANCE, where?TIPC_LOW_IMPORTANCE?is default value. TIPC_DEST_DROPPABLE:?This option governs the handling of a sent message if it cannot be delivered ??????? to its destination. If set, the message is discarded; otherwise it is returned to the sender. By default, ??????? this option is enabled for?SOCK_RDM?and?SOCK_DGRAM?sockets, and disabled otherwise. TIPC_CONN_TIMEOUT:?This option specifies the number of milliseconds?connect()?will wait before ??????? giving up because of lack of response. Default value is 8000 ms. TIPC_MCAST_BROADCAST:?Force datagram multicasts from this socket to be transmitted as ??????? bearer broadcast/multicast (instead of replicated unicast) whenever possible. TIPC_MCAST_REPLICAST:?Force datagram multicasts from this socket to be transmitted as ??????? replicated unicast instead of bearer broadcast/multicast. TIPC_GROUP_JOIN:?Join a communication group. Argument is a?struct tipc_group_req*. TIPC_GROUP_LEAVE:?Leave a communication group. No argument. ? - int shutdown(int sockfd, int howto)
Shuts down socket send and receive operations on a connected socket. The socket's peer is notified that the connection was gracefully terminated (by means of the?TIPC_CONN_SHUTDOWN?error code), rather than as the result of an error. Applications should normally call?shutdown()?to terminate a connection before calling?close(). The?howto?parameter must be set to?SHUT_RDWR, to terminate both reading and writing, since there is no support for partial shutdown in TIPC. ? - int socket(int family, int type, int protocol
Creates an endpoint for communication. TIPC supports the following socket types:?SOCK_DGRAM?and?SOCK_RDM?for datagram messaging and group messaging.?SOCK_SEQPACKET?and?SOCK_STREAM?for connection oriented messaging. The?family?parameter must be set to?AF_TIPC. The?protocol?parameter must be set to 0.
3.?LIBTIPC C API
? 许多程序员将在一段时间后围绕TIPC socket API开发一个包装器,以减少代码占用,并在添加新用户时节省工作。在tipcutils中,我们提供了一个小型但功能强大的包装器示例,用户可以复制并根据自己的需要进行修改。 ?
/* Addressing:
* - If (type == 0) struct tipc_addr is referring to a socket
* - If (node == 0) the lookup/binding scope is cluster global
*/
struct tipc_addr {
uint32_t type;
uint32_t instance;
uint32_t node;
};
uint32_t tipc_own_node(void);
char* tipc_ntoa(const struct tipc_addr *addr, char *buf, size_t len);
char* tipc_rtoa(uint32_t type, uint32_t lower, uint32_t upper,uint32_t node,
char *buf, size_t len);
/* Socket:
* - 'Rejectable': sent messages will return if rejected at destination
*/
int tipc_socket(int sk_type);
int tipc_sock_non_block(int sd);
int tipc_sock_rejectable(int sd);
int tipc_close(int sd);
int tipc_sockaddr(int sd, struct tipc_addr *addr);
int tipc_bind(int sd, uint32_t type, uint32_t lower,
uint32_t upper, uint32_t scope);
int tipc_unbind(int sd, uint32_t type, uint32_t lower, uint32_t upper);
int tipc_connect(int sd, const struct tipc_addr *dst);
int tipc_listen(int sd, int backlog);
int tipc_accept(int sd, struct tipc_addr *src);
int tipc_join(int sd, struct tipc_addr *member, bool events, bool loopback);
int tipc_leave(int sd);
/* Messaging:
* - NULL pointer parameters are always accepted
* - tipc_sendto() to an accepting socket initiates two-way connect
* - If no err pointer given, tipc_recvfrom() returns 0 on rejected message
* - If (*err != 0) buf contains a potentially truncated rejected message
* - Group event: tipc_recvfrom() returns 0; err == 0/-1 indicates up/down
*/
int tipc_recvfrom(int sd, void *buf, size_t len, struct tipc_addr *socket,
struct tipc_addr *member, int *err);
int tipc_recv(int sd, void *buf, size_t len, bool waitall);
int tipc_sendmsg(int sd, const struct msghdr *msg);
int tipc_sendto(int sd, const void *msg, size_t len,
const struct tipc_addr *dst);
int tipc_send(int sd, const void *msg, size_t len);
int tipc_mcast(int sd, const void *msg, size_t len,
const struct tipc_addr *dst);
/* Topology Server:
* - Expiration time in [ms]
* - If (expire < 0) subscription never expires
*/
int tipc_topsrv_conn(uint32_t topsrv_node);
int tipc_srv_subscr(int sd, uint32_t type, uint32_t lower,
uint32_t upper, bool all, int expire);
int tipc_srv_evt(int sd, struct tipc_addr *srv, struct tipc_addr *addr,
bool *up, bool *expired);
bool tipc_srv_wait(const struct tipc_addr *srv, int expire);
int tipc_neigh_subscr(uint32_t topsrv_node);
int tipc_neigh_evt(int sd, uint32_t *neigh_node, bool *up);
int tipc_link_subscr(uint32_t topsrv_node);
int tipc_link_evt(int sd, uint32_t *neigh_node, bool *up,
int *local_bearerid, int *remote_bearerid);
char* tipc_linkname(char *buf, size_t len, uint32_t peer, int bearerid);
|