http://blog.csdn.net/langeldep/article/details/6167137
http://liuqz926.blog.163.com/blog/static/13448936220091121104233491/
http://blog.csdn.net/zlzlei/article/details/7692987
http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/example/cpp03/multicast/receiver.cpp
http://blog.csdn.net/laohuang1122/article/details/7102827
http://www.cnblogs.com/my_life/articles/6077569.html 看這個吧,這個比較好
首先選一個多播地址和端口,數據接收方選擇一個網卡監聽這個多播地址和端口,數據發送方向這個多播地址和端口發送數據,這樣監聽了多播地址與端口的接收方就都可以收到發送方的數據了,沒有監聽的自然也就收不到了!!!
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include "my_inet.h" #include <arpa/inet.h> #define MAXBUF 256 #define PUERTO 5000 #define GRUPO "224.0.1.1" int main(void) { int fd, n, r; struct sockaddr_in srv, cli; struct ip_mreq mreq; char buf[MAXBUF]; memset( &srv, 0, sizeof(struct sockaddr_in) ); memset( &cli, 0, sizeof(struct sockaddr_in) ); memset( &mreq, 0, sizeof(struct ip_mreq) ); srv.sin_family = MY_AF_INET; srv.sin_port = htons(PUERTO); if( inet_aton(GRUPO, &srv.sin_addr ) < 0 ) { perror("inet_aton"); return -1; } if( (fd = socket( MY_AF_INET, SOCK_DGRAM, MY_IPPROTO_UDP) ) < 0 ){ perror("socket"); return -1; } if( bind(fd, (struct sockaddr *)&srv, sizeof(srv)) < 0 ){ /* 綁定一個多播地址與端口,只有該地址發來的數據才會被接收 */ perror("bind"); return -1; } if (inet_aton(GRUPO, &mreq.imr_multiaddr) < 0) { perror("inet_aton"); return -1; } inet_aton( "172.16.48.2", &(mreq.imr_interface) ); if( setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) < 0 ){ /* 將一個網卡(172.16.48.2)綁定到socket的多播地址(224.0.1.1)上 */ perror("setsockopt"); return -1; } n = sizeof(cli); while(1){ if( (r = recvfrom(fd, buf, MAXBUF, 0, (struct sockaddr *)&cli, (socklen_t*)&n)) < 0 ){ /* 正常的接收即可 */ perror("recvfrom"); }else{ buf[r] = 0; fprintf(stdout, "Mensaje desde %s: %s", inet_ntoa(cli.sin_addr), buf); } } }
這是一個非常簡單的組播客戶端,bind()操作指定只能從組播組224.0.1.1的5000端口讀數據,並顯示在終端上,下面我們通過分析該程序來了解內核的工作過程。
前面我們講過,bind操作首先檢查用戶指定的端口是否可用,然后為socket的一些成員設置正確的值,並添加到哈希表myudp_hash中。然后,協議棧每次收到UDP數據,就會檢查該數據報的源和目的地址,還有源和目的端口,在myudp_hash中找到匹配的socket,把該數據報放入該socket的接收隊列,以備用戶讀取。在這個程序中,bind操作把socket綁定到地址224.0.0.1:5000上, 該操作產生的直接結果就是,對於socket本身,下列值受影響:
struct inet_sock{
.rcv_saddr = 224.0.0.1; //對於組播而言,只接收該地址發來的組播數據;對於單播而言,只從該地址所代表的網卡接收數據
.saddr = 0.0.0.0; //發出去的數據包由該地址所代表的網卡發出去。為0,系統(在進行路由選擇時)任意選一個地址填充發出去的數據包
.sport = 5000; //通過該端口發送接收數據
.daddr = 0.0.0.0; //目的地址不確定,connect()或sendto()時會被填充
.dport = 0;
}
這五個數據表示,該套接字在發送數據包時,本地使用端口5000,本地可以使用任意一個網絡設備接口,發往的目的地址不指定。在接收數據時,只接收發往IP地址224.0.0.1的端口為5000的數據。
程序中,緊接着bind有一個setsockopt操作,它的作用是將socket加入一個組播組(用來指示使用哪個網卡接收哪個組播組的數據),因為socket要接收組播地址224.0.0.1的數據,它就必須加入該組播組。
對於UDP組播而言,bind(本地IP,port)不再適用,不是綁定本地local地址的效果,而是一種過濾規則,只接收來自該地址和端口的組播數據。
bind之后,必須要有setsockopt該動作,因為bind()操作對於組播,它會把saddr置為0,此時系統就無從下手,不知道選擇哪個網卡來接收組播數據。
同樣,對於組播數據的發送方,如果也調用了bind()操作,會導致saddr = 0; 這會使用系統默認的網卡發送組播數據。如果需要指定某個網卡來發送數據,需要setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr))來設置saddr.
結構體struct ip_mreq mreq是該操作的參數,下面是其定義:
struct ip_mreq
{
struct in_addr imr_multiaddr; // 組播組的IP地址。
struct in_addr imr_interface; // 本地某一網絡設備接口的IP地址。
};
一台主機上可能有多塊網卡,接入多個不同的子網,imr_interface參數就是指定一個特定的設備接口,告訴協議棧只想在這個設備所在的子網中加入某個組播組。有了這兩個參數,協議棧就能知道:在哪個網絡設備接口上加入哪個組播組。為了簡單起見,我們的程序中直接寫明了IP地址:在172.16.48.2所在的設備接口上加入組播組224.0.1.1。
這個操作是在網絡層上的一個選項,所以級別是SOL_IP,IP_ADD_MEMBERSHIP選項把用戶傳入的參數拷貝成了struct ip_mreqn結構體:
struct ip_mreqn
{
struct in_addr imr_multiaddr;
struct in_addr imr_address;
int imr_ifindex;
};
多了一個輸入接口的索引,暫時被拷貝成零。
該操作最終引發內核函數myip_mc_join_group執行加入組播組的操作。首先檢查imr_multiaddr是否為合法的組播地址,然后根據imr_interface的值找到對應的struct in_device結構。接下來就要為socket加入到組播組了,在inet_sock的結構體中有一個成員mc_list,它是一個結構體struct ip_mc_socklist的鏈表,每一個節點代表socket當前正加入的一個組播組,該鏈表是有上限限制的,缺省值為IP_MAX_MEMBERSHIPS(20),也就是說一個socket最多允許同時加入20個組播組。下面是struct ip_mc_socklist的定義:
struct ip_mc_socklist
{
struct ip_mc_socklist *next;
struct ip_mreqn multi;
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
struct ip_sf_socklist *sflist;
};
struct ip_sf_socklist
{
unsigned int sl_max;
unsigned int sl_count;
__u32 sl_addr[0];
};
除了multi成員,它還有一個源過濾機制。如果我們新添加的struct ip_mreqn已經存在於這個鏈表中(表示socket早就加入這個組播組了),那么不做任何事情,否則,創建一個新的struct ip_mc_socklist:
struct ip_mc_socklist
{
.next = inet->mc_list; //新節點放到鏈表頭。
.multi = 傳入的參數; //這是關鍵的組信息。
.sfmode = MCAST_EXCLUDE; //過濾掉sflist中的所有源。
.sflist = NULL; //沒有源需要過濾。
};
最后,調用myip_mc_inc_group函數在struct in_device和struct net_device的mc_list鏈表中都添上相應的組播組節點,關於這部分的細節可以在前一篇文章《初識組播2》中找到。不再重復。
==============================================================
http://blog.chinaunix.net/uid-31125416-id-5705162.html
單播(Unicast)
組播(Multicast)、多播
廣 播(Broadcast)
2.2 實現IP組播的前提條件
實現IP組播傳輸,則組播源和接收者以及兩者之間的下層網絡都必須支持組播。這包括以下幾方面:
●主機的TCP/IP實現支持發送和接收IP組播;
●主機的網絡接口支持組播;
●有一套用於加入、離開、查詢的組管理協議,即IGMP(v1,v2);
●有一套IP地址分配策略,並能將第三層IP組播地址映射到第二層MAC地址;
●支持IP組播的應用軟件;
●所有介於組播源和接收者之間的路由器、集線器、交換機、TCP/IP棧、防火牆均需支持組播;
2.3 組播地址分配與MAC地址
在組播通信中,我們需要兩種地址:一個IP組播地址和一個Ethernet組播地址。其 中,IP組播地址標識一個組播組。由於所有IP數據包都封裝在Ethernet幀中,所以還需要一個組播Ethernet地址。為使組播正常工作,主機應 能同時接收單播和組播數據,這意味着主機需要多個IP和Ethernet地址。
組播分布樹有四種基本類型:泛洪法、有源樹、有核樹和Steiner樹。
2.5 組管理協議IGMP
主機使用IGMP通知子網組播路由器,希望加入組播組;路由器使用IGMP查詢本地子網中是否有屬於某個組播組的主機。
5.2 組播應用程序接口與編程
RFC1112推薦了一些支持組播的應用程序接口:
●加入一個組播組;
●離開一個組播組;
●為調整范圍對一個組播數據的IP TTL值進行設定;
●為組播傳輸和接收設定本地的接口;
●禁止輸出的組播數據回送。
現在,許多TCP/IP實現都支持RFC1112所提到的要求,下面簡要介紹UNIX(Berkeley Socket)和Windows(Winsock) API。
5.2.1 Berkeley Socket組播API
所 有Berkeley Socket API都采用setsockopt()的“套接字選項”功能來設置(對於某些選項,getsockopt()功能可用來獲得當前的設置)。表3描述了 Berkeley BSD的set sockopt()/getsockopt()組播命令。
表3 BSD setsockopt()/getsockopt()組播命令的說明
setsockopt()/getsockopt() 組播命令 |
命令說明 |
IP_MULTICAST_TTL |
設置輸出組播數據的 TTL 值 |
IP_ADD_MEMBERSHIP |
在指定接口上加入組播組 |
IP_DROP_MEMBERSHIP |
退出組播組(在 IGMPv2 中實現) |
IP_MULTICAST_IF |
獲取默認接口或設置接口 |
IP_MULTICAST_LOOP |
禁止組播數據回送 |
對於套接字編程,首先要使用函數socket()建立一個數據報套接字,然后用bind()函數將套接字與一個地址和端口號連接起來。
為了發送一個組播數據包,需要在sendto()調用中指定一個組播地址作為目的地址(所有IP地址都使用網絡字節順序)。
為了接收一個組播數據包,需要在recvfrom()調用中指定所要接收的組播地址。
IP_MULTICAST_TTL允許將隨后的組播數據的TTL設定成從0到255之間的任何值,例如:
u_char ttl;
setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));
關於TTL的討論見上文。
通過IP_MULTICAST_IF,系統管理員可在安裝操作系統的時候為組播創建默認的網卡接口(可以通過指定一個網絡接口來發送組播數據,覆蓋默認值)。例如:
struct in_addr addr;
setsockopt(sock,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr)); //指定哪個網口用來發送組播數據
在這里,addr是對應網卡的本地IP地址,可使用一個INADDR_ANY地址來恢復使用默認的網卡接口。
為了能夠接收IP組播數據,主機必須加入某個或多個組播組(接收方需要做的事情),程序通過使用IP_ADD_MEMBERSHIP網絡接口參數向主機提出加入組播組的申請。例如:
struct ip_mreq
{
struct in_addr imn_multiaddr; /* multicast group to join */
struct in_addr imr_interface; /* interface to join on */
}mreq;
setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)); //指定在哪個網卡上接收組播數據
一個組只能與一個網絡接口相聯系;主機可把同一個網絡接口加入不同的組。
若選擇默認組播網絡接口,要將imr_interface設置為INADDR_ANY;若選擇主機其中一個本地地址,要將imr_interface設置為特定的組播接口。
若撤消一個成員資格,使用IP_DROP_MEMBERSHIP
struct ip_mreq mreq;
setsockopt(sock,IPPROTP_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(sreq));
其中mreq包含了在IP_ADD_MEMBERSHIP命令中相同的值。
5.2.2 Windows Socket組播API
基於Winsock1.1的組播編程與Berkeley Socket類似,這里不再贅述。Winsock2是Winsock1.1的擴展,除兼容Berkeley Sockets組播API外,它還定義了一套支持IP組播的協議獨立API,如表4所示:
表4 WinSock 2的協議獨立組播API說明
WSAEnum Protocol() |
獲得協議信息結構 (WASPROTOCOL_INFO) |
WSASocket() |
設置組播類型 |
WSAJoinLeaf |
加入組播組並指定角色 ( 發送者 / 接收者 ) |
WSAIoctl(…SIO_MULTICAST_SCOPE…) |
設置 IP TTL |
WSAIoctl(…SIO_MULTICAST_LOOPBACK…) |
禁止組播數據回送 |
在 Winsock2中,定義了“數據平面”(Data Plane)和“控制平面”(Control Plane)的概念,其中,數據平面決定在不同的網絡成員之間數據如何傳送;控制平面定義網絡成員的組織方式; 這兩方面的特征既可以是“有根的”(Rooted),也可以是“無根的”(Nonrooted)。在“有根的”控制平面內,存在一個特殊的組播組成員,稱 作C_root(根節點),其余的組成員稱作C_leaf(葉節點)。對“無根的”控制平面而言,只存在葉節點。
在“有根的”平面中,根節點負責組播的建立,以及同任意數量葉節點的連接。葉節點可申請加入一個特定的組播組。數據傳送只能在根節點和葉節點之間進行,根節點將數據組播到每個葉節點。
在“無根的”平面中,只存在葉節點,它們可以任意加入一個組播組。從葉節點發送的數據會組播到每一個葉節點。
由於篇幅所限,有關Winsock API的進一步討論,請參閱參考文獻<3>、<5>和MSDN。
6.1 組播的可靠性
IP組播數據包典型使用用戶數據報協議(UDP),而UDP是一種“盡力而為”(Best-effort)協議。因此,IP組播應用必定會遇到數據包丟失和亂序問題。
.3 網絡的異構性導致組播的復雜性
Internet是一個異構網絡,這種 異構性表現在很多方面。第一,Internet的低層硬件平台千差萬別,可以是Ethernet、ATM、FDDI、令牌環網、幀中繼、串行鏈路 (PSTN、xDSL)、無線網絡、衛星網絡、移動網絡等等。這些低層網絡具有不同的帶寬、硬件存取控制方式、時延特征。在多鏈路情況下,各鏈路的帶寬與 代價也可能不同。另外,某些網絡平台的數據鏈路具有非對稱性,比如xDSL和衛星網絡。第二,主機的硬件處理能力和操作系統各不相同。就操作系統而言,主 要的操作系統,如UNIX、Windows、MacOS、OS2有不同的變種和版本,對IP組播的支持程度、進程的調度與管理、TCP/IP的實現方式和 API都有差異。第三,互連設備的差異。路由器、交換機、網絡服務器在背板能力、包轉發率、支持的路由協議的互操作性。這些異構性都導致在實現IP組播網 絡中的復雜性。
比如:網絡中不同部分的帶寬不同、接收者的處理要求和處理能力不同,而所有接收者都要與同一組播源交互,這就要求采取某些方法使 得每一個接收者接收到與其接收能力和從組播源到接收者之間帶寬相適合的數據流(即公平性)。再比如:ATM面向連接的特點在IP組播傳輸中帶來了新的問 題,這使IP組播與ATM組播具有不同特點。
所以,在設計IP組播網絡時,必須充分考慮到網絡的異構性。
下面的代碼為Sender.cpp 文件代碼
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define HELLO_PORT 12345
#define HELLO_GROUP "225.0.0.37"
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, cnt;
struct ip_mreq mreq;
char *message="Hello, World!";
/* create what looks like an ordinary UDP socket */
if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0)
{
perror("socket");
exit(1);
}
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(HELLO_GROUP); //發送方的組播地址
addr.sin_port=htons(HELLO_PORT); //組播端口
/* now just sendto() our destination! */
while (1)
{
if (sendto(fd,message, strlen(message), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("sendto");
exit(1);
}
sleep(1);
}
return 0;
}
下面的代碼為 Recver.cpp代碼
http://www.cnblogs.com/my_life/articles/6065752.html
http://www.cnblogs.com/my_life/articles/6077569.html
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <time.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #define HELLO_PORT 12345 #define HELLO_GROUP "225.0.0.37" #define MSGBUFSIZE 256 int main(int argc, char *argv[]) { struct sockaddr_in addr; int fd, nbytes,addrlen; struct ip_mreq mreq; char msgbuf[MSGBUFSIZE]; u_int yes=1; /*** MODIFICATION TO ORIGINAL */ /* create what looks like an ordinary UDP socket */ if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) { perror("socket"); exit(1); } /**** MODIFICATION TO ORIGINAL */ /* allow multiple sockets to use the same PORT number */ if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) { perror("Reusing ADDR failed"); exit(1); } /*** END OF MODIFICATION TO ORIGINAL */ /* set up destination address */ memset(&addr,0,sizeof(addr)); addr.sin_family=AF_INET; addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender ,代表將會接收從任意網卡收到的數據:既能收到組播數據,又能收到單播數據*/ addr.sin_port=htons(HELLO_PORT); //組播端口 /* bind to receive address */ if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); exit(1); } /* use setsockopt() to request that the kernel join a multicast group */ mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP); //組播地址 mreq.imr_interface.s_addr=htonl(INADDR_ANY); //使用系統默認的網卡來收發組播數據 if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) //接收方才需要加入組 { perror("setsockopt"); exit(1); } /* now just enter a read-print loop */ while (1) { //ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); addrlen=sizeof(addr); if ((nbytes=recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *) &addr, (socklen_t *)&addrlen)) < 0) { perror("recvfrom"); exit(1); } puts(msgbuf); } return 0; }
下面為 編譯 sender 和 recver 的Makefile 文件
CC = gcc CXX = g++ CFLAGS = -Wall -pipe -D_DEBUG -DDEBUG -g -O0 LDFLAGS = -lstdc++ RM = /bin/rm -f MODULE_INC = -I../curl-7.21.3/include -I../boost_1_45_0 -I./ MODULE_LIB = -L../boost_1_45_0/stage/lib CFLAGS += $(MODULE_INC) LDFLAGS += $(MODULE_LIB) LIBOBJS = Sender.o Recver.o TARGET = sender recver all: $(TARGET) sender: Sender.o $(CXX) -o $@ $^ $(LDFLAGS) recver: Recver.o $(CXX) -o $@ $^ $(LDFLAGS) clean: rm -f *.o rm -f $(TARGET) # make rule %.o : %.c $(CC) $(CFLAGS) -c $^ -o $@ %.o : %.cpp $(CC) $(CFLAGS) -c $^ -o $@ install: cp -f $(TARGET) ../bin/
編譯好后就可以執行 ./sender 和 ./recver 查看執行的結果。
Time-To-Live (TTL) for Multicast Packets
The IP multicast routing protocol uses the Time To Live (TTL) field of IP datagrams to decide how "far" from a sending host a given multicast packet should be forwarded. The default TTL for multicast datagrams is 1, which will result in multicast packets going only to other hosts on the local network. A setsockopt (2) call may be used to change the TTL:
unsigned char ttl;
setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));
As the values of the TTL field increase, routers will expand the number of hops they will forward a multicast packet. To provide meaningful scope control, multicast routers enforce the following "thresholds" on forwarding based on the TTL field:
- 0
- restricted to the same host
- 1
- restricted to the same subnet
- 32
- restricted to the same site
- 64
- restricted to the same region
- 128
- restricted to the same continent
- 255
- unrestricted
===========================
組播協議允許將一台主機發送的數據通過網絡路由器和交換機復制到多個加入此組播的主機,是一種一對多的通訊方式。
組播協議與現在廣泛使用的單播協議的不同之處在於,一個主機用單播協議向n個主機發送相同的數據時,發送主機需要分別向n個主機發送,共發送n次。
一個主機用組播協議向n個主機發送相同的數據時,只要發送1次,其數據由網絡中的路由器和交換機逐級進行復制並發送給各個接收方,這樣既節省服務器資源也節省網絡主干的帶寬資源。
與廣播協議相比,只有組播接收方向路由器發出請求后,網絡路由器才復制一份數據給接收方,從而節省接收方的帶寬。而廣播方式無論接收方是否需要,網絡設備都將所有廣播信息向所有設備發送,從而大量占據接收方的接入帶寬。
組播協議的優勢:
組播協議的優勢在於當需要將大量相同的數據傳輸到不同主機時,
1.能節省發送數據的主機的系統資源和帶寬;
2.組播是有選擇地復制給有要求的主機;
3. 組播可以穿越公網廣泛傳播,而廣播則只能在局域網或專門的廣播網內部傳播;
4. 組播能節省網絡主干的帶寬;
組播協議的缺點:
與單播協議相比,組播沒有補包機制,因為組播采用的是UDP的傳輸方式,並且不是針對一個接受者,所以無法有針對的進行補包。所以直接組播協議傳輸的數據是不可靠的。
二、為什么寬帶網必須使用組播協議
自從上世紀末長城寬帶壯烈的寬帶推廣運動以來,寬帶網一直面臨種種問題,但這些問題歸結起來就是一個問題,那就是客戶端得不到與其接入帶寬相稱的足夠的數據流。
最早的長城寬帶面臨的是“寬帶無內容”的問題,客戶得不到其承諾的視頻點播等寬帶娛樂,於是投訴、退戶甚至訴諸法律。
電信憑借其雄厚的財力和電話線資源后來居上,但很快又面臨網速慢、缺內容的投訴,電信網站上的視頻點播似乎總是無盡的等待和緩沖。后來P2P軟件的出現使得某些比較專業的用戶似乎看到了希望,他們用BT、電驢等軟件互傳電影等娛樂信息也湊合了。沒多久電信和網通就高舉着和他們沒什么關系的版權大旗封殺了BT、電驢等軟件。
所有這些都是源於現在寬帶網的“上下非對稱”的金字塔結構,也就是網絡主干的帶寬遠遠小於所有用戶帶寬之和,但現在網絡使用的單播通訊協議卻要求網絡主干的帶寬等於或接近所有用戶帶寬之和。現在的狀況是一個城市或省的網絡出口主干的帶寬大約相當於其所有客戶帶寬之和的5%,也就是說假如有5%的客戶用BT軟件通過網絡全速傳輸數據,那其余95%的客戶就不要玩了。現在電信主干上的流量的75%都是P2P應用的流量,已經超過了電信所能承受的極限。
那么采用CDN技術,將網絡內容在城域網內就近緩沖行不行呢?答案是:技術上可行經濟上行不通。其需要的服務器是一個巨大的天文數字。現在的大中城市的寬帶網用戶數量都在20萬以上,以此數量來計算光購置CDN服務器就需要2億元左右!這就是為什么電信不用CDN技術來滿足客戶需求的原因。所以在服務器的服務能力和客戶機的需求上也存在着嚴重的上下非對稱結構。
那么這個死結是不是沒法解開呢?當然不是,組播協議的數據流特點就是“上下非對稱”的,也就是說,在網絡主干上的一條數據流通過每層交換機的復制可以變成無數客戶端的數據流,形成客戶端數據流之和遠大於主干數據流的金字塔結構。這一特點正好與現在的網絡結構相符。所以說,基於組播協議的流媒體寬帶娛樂可以解決這一問題。
舉例來說,使用基於組播協議的直播系統可以用一台服務器支持數萬客戶收看一個或幾個頻道的網上電視直播。假設一共提供100個頻道的電視節目,每個頻道是1M的MPEG4高清晰碼流,則無論有1萬客戶還是100萬客戶,其占用的網絡主干都是100M,而3~5台服務器硬件的投資不到100萬。
當前的網絡中有三種通訊模式:單播、廣播、組播,其中的組播出現時間最晚但同時具備單播和廣播的優點,最具有發展前景。
一、單播:
主機之間“一對一”的通訊模式,網絡中的交換機和路由器對數據只進行轉發不進行復制。如果10個客戶機需要相同的數據,則服務器需要逐一傳送,重復10次相同的工作。但由於其能夠針對每個客戶的及時響應,所以現在的網頁瀏覽全部都是采用IP單播協議。網絡中的路由器和交換機根據其目標地址選擇傳輸路徑,將IP單播數據傳送到其指定的目的地。
單播的優點:
1. 服務器及時響應客戶機的請求
2. 服務器針對每個客戶不同的請求發送不通的數據,容易實現個性化服務。
單播的缺點:
1. 服務器針對每個客戶機發送數據流,服務器流量=客戶機數量×客戶機流量;在客戶數量大、每個客戶機流量大的流媒體應用中服務器不堪重負。
2. 現有的網絡帶寬是金字塔結構,城際省際主干帶寬僅僅相當於其所有用戶帶寬之和的5%。如果全部使用單播協議,將造成網絡主干不堪重負。現在的P2P應用就已經使主干經常阻塞,只要有5%的客戶在全速使用網絡,其他人就不要玩了。而將主干擴展20倍幾乎是不可能。
二、 廣播:
主機之間“一對所有”的通訊模式,網絡對其中每一台主機發出的信號都進行無條件復制並轉發,所有主機都可以接收到所有信息(不管你是否需要),由於其不用路徑選擇,所以其網絡成本可以很低廉。有線電視網就是典型的廣播型網絡,我們的電視機實際上是接受到所有頻道的信號,但只將一個頻道的信號還原成畫面。在數據網絡中也允許廣播的存在,但其被限制在二層交換機的局域網范圍內,禁止廣播數據穿過路由器,防止廣播數據影響大面積的主機。
廣播的優點:
1. 網絡設備簡單,維護簡單,布網成本低廉
2. 由於服務器不用向每個客戶機單獨發送數據,所以服務器流量負載極低。
廣播的缺點:
1.無法針對每個客戶的要求和時間及時提供個性化服務。
2. 網絡允許服務器提供數據的帶寬有限,客戶端的最大帶寬=服務總帶寬。例如有線電視的客戶端的線路支持100個頻道(如果采用數字壓縮技術,理論上可以提供500個頻道),即使服務商有更大的財力配置更多的發送設備、改成光纖主干,也無法超過此極限。也就是說無法向眾多客戶提供更多樣化、更加個性化的服務。
3. 廣播禁止在Internet寬帶網上傳輸。
三、組播:
主機之間“一對一組”的通訊模式,也就是加入了同一個組的主機可以接受到此組內的所有數據,網絡中的交換機和路由器只向有需求者復制並轉發其所需數據。主機可以向路由器請求加入或退出某個組,網絡中的路由器和交換機有選擇的復制並傳輸數據,即只將組內數據傳輸給那些加入組的主機。這樣既能一次將數據傳輸給多個有需要(加入組)的主機,又能保證不影響其他不需要(未加入組)的主機的其他通訊。
組播的優點:
1. 需要相同數據流的客戶端加入相同的組共享一條數據流,節省了服務器的負載。具備廣播所具備的優點。
2. 由於組播協議是根據接受者的需要對數據流進行復制轉發,所以服務端的服務總帶寬不受客戶接入端帶寬的限制。IP協議允許有2億6千多萬個(268435456)組播,所以其提供的服務可以非常豐富。
3. 此協議和單播協議一樣允許在Internet寬帶網上傳輸。
組播的缺點:
1.與單播協議相比沒有糾錯機制,發生丟包錯包后難以彌補,但可以通過一定的容錯機制和QOS加以彌補。
2.現行網絡雖然都支持組播的傳輸,但在客戶認證、QOS等方面還需要完善,這些缺點在理論上都有成熟的解決方案,只是需要逐步推廣應用到現存網絡當中。
================================
、組播技術引入的必要性
隨着寬帶多媒體網絡的不斷發展,各種寬帶網絡應用層出不窮。IP TV、視頻會議、數據和資料分發、網絡音頻應用、網絡視頻應用、多媒體遠程教育等寬帶應用都對現有寬帶多媒體網絡的承載能力提出了挑戰。采用單播技術構建的傳統網絡已經無法滿足新興寬帶網絡應用在帶寬和網絡服務質量方面的要求,隨之而來的是網絡延時、數據丟失等等問題。此時通過引入IP組播技術,有助於解決以上問題。組播網絡中,即使組播用戶數量成倍增長,骨干網絡中網絡帶寬也無需增加。簡單來說,成百上千的組播應用用戶和一個組播應用用戶消耗的骨干網帶寬是一樣的,從而最大限度的解決目前寬帶應用對帶寬和網絡服務質量的要求。
二、組播技術
1、 IP組播技術體系結構
組播協議分為主機-路由器之間的組成員關系協議和路由器-路由器之間的組播路由協議。組成員關系協議包括IGMP(互連網組管理協議)。組播路由協議分為域內組播路由協議及域間組播路由協議。域內組播路由協議包括PIM-SM、PIM-DM、DVMRP等協議,域間組播路由協議包括MBGP、MSDP等協議。同時為了有效抑制組播數據在鏈路層的擴散,引入了IGMP Snooping、CGMP等二層組播協議。
IGMP建立並且維護路由器直聯網段的組成員關系信息。域內組播路由協議根據IGMP維護的這些組播組成員關系信息,運用一定的組播路由算法構造組播分發樹進行組播數據包轉發。域間組播路由協議在各自治域間發布具有組播能力的路由信息以及組播源信息,以使組播數據在域間進行轉發。
2、 組播IP地址
組播IP地址用於標識一個IP組播組。IANA把D類地址空間分配給IP組播,其范圍是從224.0.0.0到239.255.255.255。IP組播地址前四位均為1110。
八位組(1) 八位組(2) 八位組(3) 八位組(4)
1110XXXX XXXXXXXX XXXXXXXX XXXXXXXX
組播協議的地址在IP協議中屬於D類地址。
D類地址是從224.0.0.0到239.255.255.255之間的IP地址其中224.0.0.0到224.0.0.255是被保留的地址。
組播協議的地址范圍類似於一般的單播地址,被划分為兩個大的地址范圍,
239.0.0.0—239.255.255.255是私有地址,供各個內部網在內部使用,這個地址的組播不能上公網,類似於單播協議使用的192.168.X.X和10.X.X.X。
224.0.1.0—238.255.255.255是公用的組播地址,可以用於Internet上。
3、 組成員關系協議 (IGMP)
IGMP協議運行於主機和與主機直接相連的組播路由器之間,主機通過此協議告訴本地路由器希望加入並接受某個特定組播組的信息,同時路由器通過此協議周期性地查詢局域網內某個已知組的成員是否處於活動狀態
(即該網段是否仍有屬於某個組播組的成員),實現所連網絡組成員關系的收集與維護。
IGMP有三個版本,IGMPv1由RFC1112定義,目前通用的是IGMPv2,由RFC2236定義。IGMPv3目前仍然是一個草案。IGMPv1中定義了基本的組成員查詢和報告過程,IGMPv2在此基礎上添加了組成員快速離開的機制,IGMPv3中增加的主要功能是成員可以指定接收或指定不接收某些組播源的報文。這里着重介紹IGMPv2協議的功能。
IGMPv2通過查詢器選舉機制為所連網段選舉唯一的查詢器。查詢器周期性的發送普遍組查詢消息進行成員關系查詢;主機發送報告消息來應答查詢。當要加入組播組時,主機不必等待查詢消息,主動發送報告消息。當要離開組播組時,主機發送離開組消息;收到離開組消息后,查詢器發送特定組查詢消息來確定是否所有組成員都已離開。
通過上述IGMP機制,在組播路由器里建立起一張表,其中包含路由器的各個端口以及在端口所對應的子網上都有哪些組的成員。當路由器接收到某個組G的數據報文后,只向那些有G的成員的端口上轉發數據報文。至於數據報文在路由器之間如何轉發則由路由協議決定,IGMP協議並不負責。
二、 關於防火牆問題
我們的建議是將組播協議的數據流旁路繞過防火牆,即連接一條不經過防火牆的鏈路,並在端口地址列表中只允許組播地址的數據包通過;或在防火牆內部設定透明穿透bypass,即對於組播地址的數據包不作分析處理,直接轉發。其考慮基於如下幾點:
1. 現在網絡中使用的防火牆種類繁多、性能各異。但總體上來說對於處理視頻信息這樣的巨大流量都是力不從心的。
2. 組播數據流是非連接的UDP,而且需要客戶機自己加入組播才能收到組播,所以發送數據者無法通過組播定位攻擊,目前為止還未出現以組播為載體的病毒和黑客程序。