1.TIPC協(xié)議概述
TIPC是愛立信開源的透明進(jìn)程通信協(xié)議,一般用于集群系統(tǒng)中。
雖然tipc是基于socket實(shí)現(xiàn)的涎嚼,但是與一般的socket還有所區(qū)別。平時(shí)我們使用socket挑秉,無論是TCP也好法梯,UDP也好,用來標(biāo)識(shí)一對(duì)socket的通信犀概,無非是用兩個(gè)socket的IP地址和端口號(hào)立哑。比如使用UDP的socket,要發(fā)送一個(gè)datagram到另一個(gè)socket姻灶,需要指定對(duì)端的地址铛绰,這個(gè)地址是由對(duì)端設(shè)備的IP和端口號(hào)組成的。Socket是在內(nèi)核中進(jìn)行管理产喉,當(dāng)內(nèi)核檢測(cè)到socket有數(shù)據(jù)可讀時(shí)捂掰,就會(huì)通知擁有這個(gè)socket的進(jìn)程去讀取數(shù)據(jù)若皱。
這種實(shí)現(xiàn)由一種不方便,就是需要指定對(duì)端的地址尘颓,我們必須知道這個(gè)socket在哪臺(tái)設(shè)備上走触,設(shè)備IP是多少,使用的端口號(hào)是什么疤苹,才能發(fā)送數(shù)據(jù)互广。
TIPC解決了這個(gè)問題。使用TIPC卧土,我們?cè)趧?chuàng)建socket的時(shí)候惫皱,在內(nèi)核中注冊(cè)自己的服務(wù)類型,那么在發(fā)送端尤莺,只需要指定服務(wù)類型就可以由內(nèi)核路由到相應(yīng)的socket旅敷。這個(gè)時(shí)候,對(duì)應(yīng)用層來講颤霎,對(duì)端地址僅僅是一個(gè)服務(wù)類型媳谁。顯然,內(nèi)核維護(hù)著這樣一張路由表友酱,可以根據(jù)服務(wù)類型去找到對(duì)應(yīng)的socket晴音。每臺(tái)設(shè)備都有這樣的路由表,他們的信息就能夠像普通路由表一樣共享到整個(gè)集群網(wǎng)絡(luò)中去缔杉,所有設(shè)備都可以進(jìn)行socket查找锤躁。因此,有了TIPC或详,我們無需關(guān)心socket使用了哪個(gè)IP系羞,哪個(gè)端口。
Tipc還具有如下特性:
- 有些時(shí)候霸琴,多個(gè)進(jìn)程提供相同的服務(wù)椒振,僅僅是為了負(fù)載均衡或冗余備份等原因,這種情況下可以用一個(gè)整數(shù)變量instance來標(biāo)識(shí)不同的socket沈贝,但是指定同樣的服務(wù)類型杠人。此時(shí),socket是由service type和instance共同指定的宋下。發(fā)送數(shù)據(jù)的時(shí)候只需要指定service type和一個(gè)instance值即可嗡善。也可以指定service type和instance的一個(gè)區(qū)間,這種情況就是broadcast你的datagram
- 管理tipc路由表的是內(nèi)核中的name server進(jìn)程学歧。他維護(hù)著集群中所有的tipc socket罩引。在發(fā)送datagram給某個(gè)socket之前,可以向他請(qǐng)求
2.實(shí)驗(yàn)結(jié)果
本實(shí)驗(yàn)在Ubuntu 14.04環(huán)境中測(cè)試枝笨,兩臺(tái)虛擬機(jī)搭建集群環(huán)境
虛擬機(jī)操作系統(tǒng)需要先加載tipc模塊袁铐,使用命令
modprobe tipc
編譯并運(yùn)行tipcutils揭蜒,方便我們對(duì)tipc進(jìn)行配置
tipcutils代碼可以在github上獲取https://github.com/parbhu/tipcutils/tree/96413b283861d271bff23f3098565da58536c628
或者
https://github.com/TIPC/tipcutils
2.1.集群配置
配置tipc的網(wǎng)卡和地址,配置成功之后剔桨,兩臺(tái)設(shè)備上都可以發(fā)現(xiàn)tipc鄰居屉更,具體結(jié)果如下圖所示
此時(shí)就可以通過tipc進(jìn)行通信了。
2.2.通信測(cè)試
以hello_world模塊進(jìn)行測(cè)試
- 1.1.2設(shè)備當(dāng)成集群的服務(wù)端洒缀,運(yùn)行server_tipc程序
- 1.1.3設(shè)備當(dāng)成集群的客戶端瑰谜,運(yùn)行client_tipc程序
//服務(wù)端可客戶端定義應(yīng)該一樣
#define SERVER_TYPE 18888
#define SERVER_INST 17
服務(wù)端
根據(jù)參數(shù)創(chuàng)建socket之后,就一直處于監(jiān)聽socket树绩,等待數(shù)據(jù)到來萨脑,并對(duì)數(shù)據(jù)進(jìn)行處理
server_addr.family = AF_TIPC;
server_addr.addrtype = TIPC_ADDR_NAMESEQ;
server_addr.addr.nameseq.type = SERVER_TYPE;
server_addr.addr.nameseq.lower = SERVER_INST;
server_addr.addr.nameseq.upper = SERVER_INST;
server_addr.scope = TIPC_ZONE_SCOPE;
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);
}
if (0 >= recvfrom(sd, inbuf, sizeof(inbuf), 0,
(struct sockaddr *)&client_addr, &alen)) {
perror("Server: unexpected message");
}
printf("Server: Message received: %s !\n", inbuf);
if (0 > sendto(sd, outbuf, strlen(outbuf)+1, 0,
(struct sockaddr *)&client_addr, sizeof(client_addr))) {
perror("Server: failed to send");
}
客戶端
創(chuàng)建socket之后主動(dòng)發(fā)送數(shù)據(jù),監(jiān)聽socket
服務(wù)端調(diào)用wait_for_server來等待server連上
wait_for_server(SERVER_TYPE, SERVER_INST, 10000);
sd = socket(AF_TIPC, SOCK_RDM, 0);
server_addr.family = AF_TIPC;
server_addr.addrtype = TIPC_ADDR_NAME;
server_addr.addr.name.name.type = SERVER_TYPE;
server_addr.addr.name.name.instance = SERVER_INST;
server_addr.addr.name.domain = 0;
if (0 > sendto(sd, buf, strlen(buf)+1, 0,
(struct sockaddr*)&server_addr, sizeof(server_addr))) {
perror("Client: failed to send");
exit(1);
}
if (0 >= recv(sd, buf, sizeof(buf), 0)) {
perror("Client: unexpected response");
exit(1);
}