歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> 簡介Linux下的多播編程

簡介Linux下的多播編程

日期:2017/3/3 16:27:41   编辑:關於Linux

下面就開始我們的多播編程了:

一、多播的概念

多播,也稱為“組播”,將網絡中同一業務類型主機進行了邏輯上的分組,進行數據收發的時候其數據僅僅在同一分組中進行,其他的主機沒有加入此分組不能收發對應的 數據。

在 廣域網上廣播的時候,其中的交換機和路由器只向需要獲取數據的主機復制並轉發數據。主機可以向路由器請求加入或退出某個組,網絡中的路由器和交換機有選擇 地復制並傳輸數據,將數據僅僅傳輸給組內的主機。多播的這種功能,可以一次將數據發送到多個主機,又能保證不影響其他不需要(未加入組)的主機的其他通 信。

相對於傳統的一對一的單播,多播具有如下的優點:

具有同種業務的主機加入同一數據流,共享同一通道,節省了帶寬和服務器的優點,具有廣播的優點而又沒有廣播所需要的帶寬。

服務器的總帶寬不受客戶端帶寬的限制。由於組播協議由接收者的需求來確定是否進行數據流的轉發,所以服務器端的帶寬是常量,與客戶端的數量無關。

與單播一樣,多播是允許在廣域網即Internet上進行傳輸的,而廣播僅僅在同一局域網上才能進行。

組播的缺點:

多播與單播相比沒有糾錯機制,當發生錯誤的時候難以彌補,但是可以在應用層來實現此種功能。

多播的網絡支持存在缺陷,需要路由器及網絡協議棧的支持。

多播的應用主要有網上視頻、網上會議等。

二、 廣域網的多播

多播的地址是特定的,D類地址用於多播。D類IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之間的IP地址,並被劃分為局部連接多播地址、預留多播地址和管理權限多播地址3類:

局部多播地址:在224.0.0.0~224.0.0.255之間,這是為路由協議和其他用途保留的地址,路由器並不轉發屬於此范圍的IP包。

預留多播地址:在224.0.1.0~238.255.255.255之間,可用於全球范圍(如Internet)或網絡協議。

管理權限多播地址:在239.0.0.0~239.255.255.255之間,可供組織內部使用,類似於私有IP地址,不能用於Internet,可限制多播范圍。

三、Linux下多播編程

Linux下多播編程的基本步驟:

多播程序框架主要包含套接字初始化、設置多播超時時間、加入多播組、發送數據、接收數據以及從多播組中離開幾個方面。其步驟如下:

(1)建立一個socket。

(2)然後設置多播的參數,例如超時時間TTL、本地回環許可LOOP等。

(3)加入多播組。

(4)發送和接收數據。

(5)從多播組離開。

多播程序設計使用setsockopt()函數和getsockopt()函數來實現,組播的選項是IP層的。

1.選項IP_MULTICASE_TTL

選項IP_MULTICAST_TTL允許設置超時TTL,范圍為0~255之間的任何值,例如:

unsigned char ttl=255;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));

2.選項IP_MULTICAST_IF

選項IP_MULTICAST_IF用於設置組播的默認默認網絡接口,會從給定的網絡接口發送,另一個網絡接口會忽略此數據。例如:

struct in_addr addr;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr));

參數addr是希望多播輸出接口的IP地址,使用INADDR_ANY地址回送到默認接口。

默認情況下,當本機發送組播數據到某個網絡接口時,在IP層,數據會回送到本地的回環接口,選項IP_MULTICAST_LOOP用於控制數據是否回送到本地的回環接口。例如:

unsigned char loop;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));參數loop設置為0禁止回送,設置為1允許回送。

3.選項IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP

加入或者退出一個多播組,通過選項IP_ADD_MEMBERSHIP和IP_DROP_MEMBER- SHIP,對一個結構struct ip_mreq類型的變量進行控制,struct ip_mreq原型如下:

struct ip_mreq

{

struct in_addr imn_multiaddr; /*加入或者退出的廣播組IP地址*/

struct in_addr imr_interface; /*加入或者退出的網絡接口IP地址*/

};

選項IP_ADD_MEMBERSHIP用於加入某個多播組,之後就可以向這個多播組發送數據或者從多播組接收數據。此選項的值為mreq結構,成員imn_multiaddr是需要加入的多播組IP地址,成員imr_interface是本機需要加入廣播組的網絡接口IP地址。例如:

struct ip_mreq mreq;

setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

緊接著上篇博文《Linux下多播編程<一>》,我們這篇文章就一個真實的程序來說明多播編程問題。

一個多播例子的客戶端

多播組的IP地址為224.0.0.88,端口為8888,當客戶端接收到多播的數據後將打印出來。客戶端只有在加入多播組後才能接受多播組的數據,因此多播客戶端在接收多播組的數據之前需要先加入多播組,當接收完畢後要退出多播組。

/*    
*broadcast_client.c - 多播的客戶端    
*/    
#define MCAST_PORT 8888;    
#define MCAST_ADDR "224.0.0.88"     /*一個局部連接多播地址,路由器不進行轉發*/    
#define MCAST_INTERVAL 5                        /*發送間隔時間*/    
#define BUFF_SIZE 256                           /*接收緩沖區大小*/    
int main(int argc, char*argv[])    
{      
    int s;                                      /*套接字文件描述符*/    
    struct sockaddr_in local_addr;              /*本地地址*/    
    int err = -1;    
           
    s = socket(AF_INET, SOCK_DGRAM, 0);     /*建立套接字*/    
    if (s == -1)    
    {    
        perror("socket()");    
        return -1;    
    }      
           
                                                /*初始化地址*/    
    memset(&local_addr, 0, sizeof(local_addr));    
    local_addr.sin_family = AF_INET;    
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
    local_addr.sin_port = htons(MCAST_PORT);    
           
                                                /*綁定socket*/    
    err = bind(s,(struct sockaddr*)&local_addr, sizeof(local_addr)) ;    
    if(err < 0)    
    {    
        perror("bind()");    
        return -2;    
    }    
           
                                                /*設置回環許可*/    
    int loop = 1;    
    err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop));    
    if(err < 0)    
    {    
        perror("setsockopt():IP_MULTICAST_LOOP");    
        return -3;    
    }    
           
    struct ip_mreq mreq;                                    /*加入廣播組*/    
    mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR); /*廣播地址*/    
    mreq.imr_interface.s_addr = htonl(INADDR_ANY); /*網絡接口為默認*/    
                                                        /*將本機加入廣播組*/    
    err = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof    
    (mreq));    
    if (err < 0)    
    {    
        perror("setsockopt():IP_ADD_MEMBERSHIP");    
        return -4;    
    }    
           
    int times = 0;    
    int addr_len = 0;    
    char buff[BUFF_SIZE];    
    int n = 0;    
                                        /*循環接收廣播組的消息,5次後退出*/    
    for(times = 0;times<5;times++)    
    {    
        addr_len = sizeof(local_addr);    
        memset(buff, 0, BUFF_SIZE);                 /*清空接收緩沖區*/    
                                                    /*接收數據*/    
        n = recvfrom(s, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr,    
        &addr_len);    
        if( n== -1)    
        {    
            perror("recvfrom()");    
        }    
                                                    /*打印信息*/    
        printf("Recv %dst message from server:%s\n", times, buff);    
        sleep(MCAST_INTERVAL);    
    }    
           
                                                    /*退出廣播組*/
    err = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof    
    (mreq));    
               
    close(s);    
    return 0;    
}

一個多播例子的服務器端

下面是一個多播服務器的例子。多播服務器的程序設計很簡單,建立一個數據包套接字,選定多播的IP地址和端口,直接向此多播地址發送數據就可以了。多播服務器的程序設計,不需要服務器加入多播組,可以直接向某個多播組發送數據。

下面的例子持續向多播IP地址"224.0.0.88"的8888端口發送數據"BROADCAST TEST DATA",每發送一次間隔5s。

/*    
*broadcast_server.c - 多播服務程序    
*/    
#define MCAST_PORT 8888;    
#define MCAST_ADDR "224.0.0.88"/    /*一個局部連接多播地址,路由器不進行轉發*/    
#define MCAST_DATA "BROADCAST TEST DATA"            /*多播發送的數據*    
#define MCAST_INTERVAL 5                            /*發送間隔時間*/    
int main(int argc, char*argv)    
{    
    int s;    
    struct sockaddr_in mcast_addr;         
    s = socket(AF_INET, SOCK_DGRAM, 0);         /*建立套接字*/    
    if (s == -1)    
    {    
        perror("socket()");    
        return -1;    
    }    
           
    memset(&mcast_addr, 0, sizeof(mcast_addr));/*初始化IP多播地址為0*/    
    mcast_addr.sin_family = AF_INET;                /*設置協議族類行為AF*/    
    mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);/*設置多播IP地址*/    
    mcast_addr.sin_port = htons(MCAST_PORT);        /*設置多播端口*/    
           
                                                    /*向多播地址發送數據*/    
    while(1) {    
        int n = sendto(s,                           /*套接字描述符*/    
                                    MCAST_DATA,     /*數據*/    
                                    sizeof(MCAST_DATA),    /*長度*/    
                                    0,    
                                    (struct sockaddr*)&mcast_addr,    
                                    sizeof(mcast_addr)) ;    
        if( n < 0)    
        {    
            perror("sendto()");    
            return -2;    
        }          
               
        sleep(MCAST_INTERVAL);                          /*等待一段時間*/
    }    
           
    return 0;    
}

本文出自 “驿落黃昏” 博客,請務必保留此出處http://yiluohuanghun.blog.51cto.com/3407300/1084520

Copyright © Linux教程網 All Rights Reserved