linux udp 單播 組播 廣播實現
前面介紹的TCP/IP知識都是基於單播,即一對一的方式,本節介紹一對多的廣播方式。廣播是由一個主機發向一個網路上所有主機的操作方式。例如在一個區域網內進行廣播,同一子網內的所有主機都可以收到此廣播發送的資料。 11.2.1 廣播的IP地址要使用廣播,需要了解IPv4特定的廣播地址。IP地址分為左邊的網路ID部分以及右邊的主機ID部分。廣播地址所用的IP地址將表示主機ID的位全部設定為1。網絡卡正確配置以後,可以用下面的命令來顯示所選用介面的廣播地址。 # ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:A0:4B:06:F4:8D inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1 RX packets:1955 errors:0 dropped:0 overruns:0 frame:31 TX packets:1064 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 Interrupt:9 Baseaddress:0xe400 第二行輸出資訊說明 廣播地址255.255.255.255是一種特殊的廣播地址,這種格式的廣播地址是向全世界進行廣播,但是卻有更多的限制。一般情況下,這種廣播型別不會被路由器路由,而一個更為特殊的廣播地址,例如192.168.0.255也許會被路由,這取決於路由器的配置。 通用的廣播地址在不同的環境中的含義不同。例如,IP地址255.255.255.255,一些UNIX系統將其解釋為在主機的所有網路介面上進行廣播,而有的 如果必須向每個網路介面廣播,程式在廣播之前應執行下面的步驟。 (1)確定下一個或第一個介面名字。 (2)確定介面的廣播地址。 (3)使用這個廣播地址進行廣播。 (4)對於系統中其餘的活動網路介面重複執行步驟(1)~步驟(3)。 在執行完這些步驟以後,就可以認為已經對每一個介面進行廣播。 11.2.2 廣播與單播的比較廣播和單播的處理過程是不同的,單播的資料只是收發資料的特定主機進行處理,而廣播的資料整個區域網都進行處理。 例如在一個乙太網上有3個主機,主機的配置如表11.4所示。 表11.4 某區域網中主機的配置情況
單播的示意圖如圖11.3所示,主機A向主機B傳送UDP資料報,傳送的目的IP為192.168.1.151,埠為80,目的MAC地址為00:00:00:00:00:02。此資料經過UDP層、IP層,到達資料鏈路層,資料在整個乙太網上傳播,在此層中其他主機會判斷目的MAC地址。主機C的MAC地址為00:00:00:00:00:03,與目的MAC地址00:00:00:00:00:02不匹配,資料鏈路層不會進行處理,直接丟棄此資料。 圖 11.3 單播的乙太網示意圖主機B的MAC地址為00:00:00:00:00:02,與目的MAC地址00:00:00:00:00:02一致,此資料會經過IP層、UDP層,到達接收資料的應用程式。 廣播的示意圖如圖11.4所示,主機A向整個網路傳送廣播資料,傳送的目的IP為192.168.1.255,埠為80,目的MAC地址為FF:FF:FF:FF:FF:FF。此資料經過UDP層、IP層,到達資料鏈路層,資料在整個乙太網上傳播,在此層中其他主機會判斷目的MAC地址。由於目的MAC地址為FF:FF:FF:FF:FF:FF,主機C和主機B會忽略MAC地址的比較(當然,如果協議棧不支援廣播,則仍然比較MAC地址),處理接收到的資料。 主機B和主機C的處理過程一致,此資料會經過IP層、UDP層,到達接收資料的應用程式。 圖 11.4 廣播的乙太網示意圖11.2.3 廣播的示例本節中是一個伺服器地址發現的程式碼,假設伺服器為A,客戶端為B。客戶端在某個區域網啟動的時候,不知道本區域網內是否有適合的伺服器存在,它會使用廣播在本區域網內傳送特定協議的請求,如果有伺服器響應了這種請求,則使用響應請求的IP地址進行連線,這是一種伺服器/客戶端自動發現的常用方法。 1.廣播例子簡介如圖11.5所示為使用廣播的方法發現區域網上伺服器的IP地址。伺服器在區域網上偵聽,當有資料到來的時候,判斷資料是否有關鍵字IP_FOUND,當存在此關鍵字的時候,傳送IP_FOUND_ACK到客戶端。客戶端判斷是否有伺服器的響應IP_FOUND請求,並判斷響應字串是否包含IP_FOUND_ACK來確定區域網上是否存在伺服器,如果有伺服器的響應,則根據recvfrom()函式的from變數可以獲得伺服器的IP地址。 圖 11.5 利用廣播進行伺服器IP地址的發現2.廣播的伺服器端程式碼伺服器的程式碼如下,伺服器等待客戶端向某個埠傳送資料,如果資料的格式正確,則伺服器會向客戶端傳送響應資料。 01 02 #define IP_FOUND "IP_FOUND" /*IP發現命令*/ 03 #define IP_FOUND_ACK "IP_FOUND_ACK" /*IP發現應答命令*/ 04 void HandleIPFound(void*arg) 05 { 06 #define BUFFER_LEN 32 07 int ret = -1; 08 SOCKET sock = -1; 09 struct sockaddr_in local_addr; /*本地地址*/ 10 struct sockaddr_in from_addr; /*客戶端地址*/ 11 int from_len; 12 int count = -1; 13 fd_set readfd; 14 char buff[BUFFER_LEN]; 15 struct timeval timeout; 16 timeout.tv_sec = 2; /*超時時間2s*/ 17 timeout.tv_usec = 0; 18 19 DBGPRINT("==>HandleIPFound\n"); 20 21 sock = socket(AF_INET, SOCK_DGRAM, 0); /*建立資料報套接字*/ 22 if( sock < 0 ) 23 { 24 DBGPRINT("HandleIPFound: socket init error\n"); 25 return; 26 } 27 28 /*資料清零*/
29 memset((void*)&local_addr,
0, sizeof(struct sockaddr_in)); 30 local_addr.sin_family = AF_INET; /*協議族*/ 31 local_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*本地地址*/ 32 local_addr.sin_port = htons(MCAST_PORT); /*偵聽埠*/ 33 /*繫結*/
34 ret = bind(sock, (struct sockaddr*)&local_addr,
sizeof(local_ 35 if(ret != 0) 36 { 37 DBGPRINT("HandleIPFound:bind error\n"); 38 return; 39 } 40 41 /*主處理過程*/ 42 while(1) 43 { 44 /*檔案描述符集合清零*/ 45 FD_ZERO(&readfd); 46 /*將套接字檔案描述符加入讀集合*/ 47 FD_SET(sock, &readfd); 48 /*select偵聽是否有資料到來*/ 49 ret = selectsocket(sock+1, &readfd, NULL, NULL, &timeout); 50 switch(ret) 51 { 52 case -1: 53 /*發生錯誤*/ 54 break; 55 case 0: 56 /*超時*/ 57 //超時所要執行的程式碼 58 59 break; 60 default: 61 /*有資料到來*/ 62 if( FD_ISSET( sock, &readfd ) ) 63 { 64 /*接收資料*/
65 count
= recvfrom( sock, buff, BUFFER_LEN, 0, 66 DBGPRINT( "Recv msg is %s\n", buff );
67 if(
strstr( buff, IP_FOUND ) ) |