TIPC 服务追踪
服务订阅
应用程序可以使用服务地址{Type:TIPC_TOP_SRV(1),Instance:TIPC_TOP_SRV(1)}来建立到tipc内置拓扑服务的SOCK_SEQPACKET类型的连接来访问拓扑服务。然后应用程序向内置拓扑服务发送一或多个服务订阅消息,指明想跟踪或想订阅的服务范围。拓扑服务在接受到应用程序的订阅请求后,只要匹配的地址被集群内的套接字绑定或解除,就向服务程序发送服务事件消息,一个程序可以使用一个连接同时激活多个订阅。
//连接内置拓扑服务
struct sockaddr_tipc topsrv;
struct tipc_subscr subscr;
struct tipc_event event;
int sd;
printf("TIPC Topology subscriber started\n");
/* Connect to topology server */
memset(&topsrv, 0, sizeof(topsrv));
topsrv.family = AF_TIPC;
topsrv.addrtype = TIPC_SERVICE_ADDR;
topsrv.addr.name.name.type = TIPC_TOP_SRV;
topsrv.addr.name.name.instance = TIPC_TOP_SRV;
sd = socket (AF_TIPC, SOCK_SEQPACKET, 0);
if (0 > connect(sd, (struct sockaddr *)&topsrv, sizeof(topsrv))) {
perror("Client: failed to connect to topology server");
exit(1);
}
printf("Client: connected to topology server\n");
应用程序和拓扑服务之间的消息交换是完全异步的,应用程序可以随时发出新的订阅请求,拓扑服务可以随时向应用程序响应有关匹配绑定的事件。(可以随时订阅获取到整个集群中的所有tipc进程)。
应用程序和拓扑服务之间的显式连接默认不会中断,除非应用程序终止它,或直到拓扑服务遇到需要他终止连接的错误。当连接结束后,TIPC会自动取消所有相关的订阅。
拓扑服务是位于本机,他的逻辑地址是{1,1,1},当tipc节点加入集群后,可以连接到其他集群节点的拓扑服务器,用户就可以构建和跟踪整个集群的整体连接矩阵。
$ tipc nametable show
Type Lower Upper Scope Port Node
0 584168684 584168684 cluster 0 709cd1229c28
0 2535114096 2535114096 cluster 0 4851c570df4b
1 1 1 node 2124271872 4851c570df4b
2 584168684 584168684 node 0 709cd1229c28
18888 6 53 cluster 316360070 709cd1229c28
18888 6 53 cluster 316360070 709cd1229c28
18888 6 53 cluster 1214279559 4851c570df4b
18888 6 53 cluster 1214279559 4851c570df4b
18888 54 55 cluster 3715803002 709cd1229c28
18888 54 55 cluster 316360070 709cd1229c28
18888 54 55 cluster 3332551435 4851c570df4b
18888 54 55 cluster 1214279559 4851c570df4b
集群拓扑订阅
当TIPC与另一个节点建立连接时,它会在绑定表中内部创建一个绑定
{type = TIPC_NODE_STATE, instance = peer node hash number},这可以使得节点上的应用程序随时跟踪访问对等节点。
集群连接订阅
当一个TIPC节点与另一个TIPC节点建立链接时,它会在绑定表中内部创建一个绑定**{type = TIPC_NODE_STATE, instance = peer node hash number}**,这使得节点上的应用程序可以随时跟踪访问对等节点。有几个链接,就有几个绑定,以跟踪对等节点。当一个tipc节点加入tipc集群时,会与集群内的每一个节点建立连接。
$ tipc nametable show
Type Lower Upper Scope Port Node
0 584168684 584168684 cluster 0 709cd1229c28 #0 表示对等节点的可用性
0 2535114096 2535114096 cluster 0 4851c570df4b
0 4277592413 4277592413 cluster 0 347df6fe699c
1 1 1 node 2124271872 4851c570df4b #1 表示拓扑服务器
2 584168684 584168684 node 0 709cd1229c28 #2 表示单个链接的可用性
2 4277592413 4277592413 node 0 347df6fe699c
18888 6 53 cluster 316360070 709cd1229c28
18888 6 53 cluster 316360070 709cd1229c28
18888 6 53 cluster 1214279559 4851c570df4b
18888 6 53 cluster 1214279559 4851c570df4b
18888 54 55 cluster 3715803002 709cd1229c28
18888 54 55 cluster 316360070 709cd1229c28
18888 54 55 cluster 3332551435 4851c570df4b
18888 54 55 cluster 1214279559 4851c570df4b
套接字接口
地址类型
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;
};
tipc_subscr
- seq : 要订阅的服务地址的范围,如果是单个地址,则seq.lower和seq.upper的值应该相等
- timeout:指定订阅的生命周期,单位是ms。如何此字段设置为TIPC_WAIT_FOREVER(uint32_t ~0),则订阅将永不过期。
- filter:过滤器,一个位字段,指定拓扑服务如何对订阅进行操作,有三种值可以选择:
- TIPC_SUB_SERVICE:只订阅边缘事件,当从绑定表删除事件时,只匹配最后一个删除事件。此事件类型仅通知当前集群中是否存在任何匹配的绑定
- TIPC_SUB_PORTS:订阅绑定表的每一个更新,可以跟踪集群中每个单独存在的匹配服务绑定
- TIPC_SUB_CANCEL:取消订阅
TIPC_SUB_SERVICE和TIPC_SUB_PORTS的区别
SUB_SERVICE:
subscr.seq.type = (argc > 1) ? htonl(atoi(argv[1])) : htonl(SERVER_TYPE); subscr.seq.lower = htonl(0); subscr.seq.upper = htonl(100); subscr.timeout = (argc > 2) ? htonl(atoi(argv[2])) : htonl(TIMEOUT); subscr.filter = htonl(TIPC_SUB_SERVICE); subscr.usr_handle[0] = (argc > 3) ? (char)atoi(argv[3]) : (char)2; if (send(sd, &subscr, sizeof(subscr), 0) != sizeof(subscr)) { perror("Client: failed to subscribe to subscription server name"); exit(1); } print_sub("Client: issued subscription to", &subscr);SUB_PORTS:
subscr.seq.type = htonl(0); subscr.seq.lower = htonl(0); subscr.seq.upper = htonl(~0); subscr.timeout = htonl(TIPC_WAIT_FOREVER); subscr.filter = htonl(TIPC_SUB_PORTS); subscr.usr_handle[0] = (char)3;server.c
#include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <linux/tipc.h> #define SERVER_TYPE 18888 #define SERVER_INST_LOWER 6 #define SERVER_INST_UPPER 53 #ifndef TIPC_SERVICE_RANGE #define TIPC_SERVICE_RANGE 1 #endif int main(int argc, char *argv[]) { struct sockaddr_tipc server_addr; int sd; server_addr.family = AF_TIPC; server_addr.addrtype = TIPC_SERVICE_RANGE; server_addr.addr.nameseq.type = SERVER_TYPE; server_addr.addr.nameseq.lower = SERVER_INST_LOWER; server_addr.addr.nameseq.upper = SERVER_INST_UPPER; server_addr.scope = TIPC_ZONE_SCOPE; /* Make server available */ sd = socket(AF_TIPC, SOCK_RDM, 0); if (0 != bind(sd, (struct sockaddr *)&server_addr, sizeof(server_addr))) { printf("Server: failed to bind port name\n"); exit(1); } printf("Server: bound port A to {%u,%u,%u} scope %u\n", server_addr.addr.nameseq.type, server_addr.addr.nameseq.lower, server_addr.addr.nameseq.upper, server_addr.scope); /* Bind name a second time, to get a higher share of the calls */ if (0 != bind(sd, (struct sockaddr *)&server_addr, sizeof(server_addr))) { printf("Server: failed to bind port name\n"); exit(1); } printf("Server: bound port A to name sequence {%u,%u,%u} scope %u\n", server_addr.addr.nameseq.type, server_addr.addr.nameseq.lower, server_addr.addr.nameseq.upper, server_addr.scope); /* Bind a third time, with a different name sequence */ server_addr.addr.nameseq.lower = SERVER_INST_UPPER+1; server_addr.addr.nameseq.upper = SERVER_INST_UPPER+2; if (0 != bind(sd, (struct sockaddr *)&server_addr, sizeof(server_addr))) { printf("Server: failed to bind port name\n"); exit(1); } printf("Server: bound port A to name sequence {%u,%u,%u} scope %u\n", server_addr.addr.nameseq.type, server_addr.addr.nameseq.lower, server_addr.addr.nameseq.upper, server_addr.scope); /* Bind a second port to the same sequence */ sd = socket(AF_TIPC, SOCK_RDM,0); if (0 != bind(sd, (struct sockaddr *)&server_addr, sizeof(server_addr))) { printf("Server: failed to bind port name\n"); exit(1); } printf("Server: bound port B to name sequence {%u,%u,%u} scope %u\n", server_addr.addr.nameseq.type, server_addr.addr.nameseq.lower, server_addr.addr.nameseq.upper, server_addr.scope); printf("\nServer: port names remain published until server is killed\n"); /* Wait for user to kill server */ while (1) sleep(1); exit(0); }server.c 启动一个服务器,同一个逻辑地址绑定到了相同或不同的物理地址(socket上)
18888 6 53 cluster 1214279559 4851c570df4b 18888 6 53 cluster 1214279559 4851c570df4b 18888 54 55 cluster 3332551435 4851c570df4b 18888 54 55 cluster 1214279559 4851c570df4b$ tipc socket list ─╯ socket 3332551435 bound to {18888,54,55} socket 1214279559 bound to {18888,54,55} bound to {18888,6,53} bound to {18888,6,53} socket 2124271872 bound to {1,1,1}在两个节点上分别启动server(两个节点启动的内容完全一样,他们拥有相同的逻辑地址)
当filter类型为TIPC_SUB_SERVICE时,结果为:
Client: received event for published {18888,6,53} port id <22d1b4ec:1757026886> associated with network node 22d1b4ec generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,54,55} port id <22d1b4ec:1757026886> associated with network node 22d1b4ec generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2相同类型的服务地址(即逻辑地址只发现了一次)
当filter类型为TIPC_SUB_PORTS时,结果为:
Client: received event for published {18888,6,53} port id <971ac570:3489662746> associated with network node 971ac570 generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,6,53} port id <971ac570:3489662746> associated with network node 971ac570 generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,6,53} port id <22d1b4ec:1757026886> associated with network node 22d1b4ec generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,6,53} port id <22d1b4ec:1757026886> associated with network node 22d1b4ec generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,54,55} port id <971ac570:3473823716> associated with network node 971ac570 generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,54,55} port id <971ac570:3489662746> associated with network node 971ac570 generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,54,55} port id <22d1b4ec:506103488> associated with network node 22d1b4ec generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2 Client: received event for published {18888,54,55} port id <22d1b4ec:1757026886> associated with network node 22d1b4ec generated by subscription to {18888,0,100}, timeout 4294967295, user ref: 2可以看到所有的服务地址,即使是相同的服务地址(在同一节点的相同服务地址或在不同节点的相同服务地址),也都被发现了。
所以TIPC_SUB_SERVICE和TIPC_SUB_PORTS 的区别是:
SERVICE:集群中如果有相同的服务地址,那么订阅服务器只返回第一个匹配的绑定事件(也就是说相同类型的服务地址只发现一次),在服务退出时,只匹配最后一个从绑定表中删除的事件(相同的服务地址,最后一个从绑定表中删除时,才会返回删除事件)。
PORTS:从绑定表中匹配所有的匹配事件(发现或删除)。
- user_handle : 64位字段,用户自己设置。
tipc_event
订阅发送后,订阅者将收到0或多个返回消息,返回消息结构由tipc_event结构体定义.
- event: 表示事件的类型,由三个类型
- TIPC_PUBLISHED:绑定表中找到匹配的绑定,则返回一个或多个匹配项的事件(由subscr中的filter指定),此后,每次更改也都会返回一个事件(也取决于subscr中filter的内容)。
- TIPC_WITHDRAWN:从绑定表中删除匹配的绑定,也是返回一个或多个匹配项的事件(由subscr中的filter指定)。
- TIPC_SUBSCR_TIMEOUT:订阅过期,由给定的超时值指定,并已经被删除。
- found_lower/found_upper:匹配绑定的范围,此范围不一定与订阅范围相同,两者只要有交集就可以。
- port:匹配socket的socket地址
- s:原始订阅请求的完整副本