c++ 網絡編程(六)LINUX下 socket編程 多播與廣播 實現一次發送全部組客戶端都能接收到

 

原文做者:aircrafthtml

原文連接:https://www.cnblogs.com/DOMLX/p/9614288.html前端

 

 

一.多播python

鍥子:有這麼一種狀況,網絡電臺可能須要同時向成千上萬的用戶傳輸相同的數據,若是用咱們之前講過的傳輸形式,每一個用戶都傳輸一次,這樣確定是不合理的。所以,就引入了多播技術來解決這個問題,它能夠同時向大量用戶發送相同數據。其基本原理是這樣的:有個多播組,只要加入這個組裏的全部客服端,服務端發送的數據它們都能收到,具體傳輸到多播組裏的每一個客戶是由路由完成的(若是路由器不支持多播或網絡堵塞,實現多播也會使用隧道技術)c++

 

    • 多播的數據傳輸特色以下:
      1,多播服務器端針對特定多播組,只需發送1次數據,該組內的全部全部客服端都能接收數據。
      2,多播組數可在IP地址範圍內任意增長。編程

    • 設置生存時間和加入多播組的方法
      1,設置生存時間:只指服務端發送的數據包最遠能傳遞的距離,用整數表示,而且每通過1個路由器就減1,當爲0時,該數據包沒法再被傳遞,只能銷燬。所以,這個值設置過大將影響網絡流量。固然,設置太小也會沒法傳遞到目標(經過套接字可選項設置,示例代碼中有使用方法)。後端

      2,加入多播組:也是經過套接字可選項設置,示例代碼中有使用方法,這裏只介紹多播組的結構體ip_mreq。服務器

    •  

      struct ip_mreq
      {
      struct in_addr imr_multiaddr; //多播組的IP地址
      struct in_addr imr_interface; //加入的客服端主機IP地址 網絡

       

      }app

       

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define TTL 64    //數據包生存時間,即最多能夠傳遞通過第64個路由時銷燬
#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, const char * argv[]) {
    int send_sock;
    struct sockaddr_in mul_adr;
    int time_live = TTL;
    FILE *fp;
    char buf[BUF_SIZE];
    if (argc != 3) {
        printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
        exit(1);
    }

    //基於UDP的多播
    send_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&mul_adr, 0, sizeof(mul_adr));
    mul_adr.sin_family = AF_INET;
    mul_adr.sin_addr.s_addr = inet_addr(argv[1]);
    mul_adr.sin_port = htons(atoi(argv[2]));

    //設置生存時間(除了這裏其它基本和UDP編寫同樣)
    setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time_live, sizeof(time_live));

    if((fp = fopen("/Users/app05/Desktop/test.txt", "r")) == NULL)
        error_handling("fopen() error");

    while (!feof(fp)) //若是文件結束,則返回非0值,不然返回0
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&mul_adr, sizeof(mul_adr));
        sleep(1); //只是爲了加個傳輸數據時間間隔,沒有特殊意義
    }

    fclose(fp);
    close(send_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

 

 

接收者(receiver):機器學習

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, const char * argv[]) {
    int recv_sock;
    int str_len;
    char buf[BUF_SIZE];
    struct sockaddr_in adr;
    struct ip_mreq join_adr; //多播組結構體

    if(argc != 3)
    {
        printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
        exit(1);
    }

    recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&adr, 0, sizeof(adr));
    adr.sin_family = AF_INET;
    adr.sin_addr.s_addr = htonl(INADDR_ANY);
    adr.sin_port = htons(atoi(argv[2]));

    if(bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)
        error_handling("bind() error");

    //加入多播組
    join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]);
    join_adr.imr_interface.s_addr = htonl(INADDR_ANY);
    setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));

    while (1) {
        str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0);//只須要多播組IP地址,不關心本身主機地址
        if(str_len < 0)
            break;
        buf[str_len] = 0;
        fputs(buf, stdout);
    }

    close(recv_sock);
    return 0;
}


void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

 

 

二.廣播

廣播在功能上和多播是同樣的,都是同時能夠向大量客戶傳遞數據。但他們在網絡範圍上有區別,多播能夠跨越不一樣的網絡,只要加入了多播組就能接收數據。但廣播只能向同一網絡中的主機傳輸數據。
廣播分爲:直接廣播與本地廣播,直接廣播sender的IP地址只需指定網絡地址,主機地址所有填255。這樣處在這個網絡地址裏的全部主機就能夠接收數據了。而本地廣播sender的IP地址寫255.255.255.255,這樣本地網絡全部主機就能夠接收數據了。

//將SO_BROADCAST可選項設置爲1就表示開啓了套接字廣播功能,默認是關閉的。
int bcast = 1;
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void *) &bcast, sizeof(bcast));

 

 

下面就多播的代碼示例稍做修改,本地廣播的示例以下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define TTL 64    //數據包生存時間,即最多能夠傳遞通過第64個路由時銷燬
#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, const char * argv[]) {
    int send_sock;
    struct sockaddr_in mul_adr;
    int time_live = TTL;
    FILE *fp;
    char buf[BUF_SIZE];
    if (argc != 3) {
        printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
        exit(1);
    }

    //基於UDP的多播
    send_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&mul_adr, 0, sizeof(mul_adr));
    mul_adr.sin_family = AF_INET;
    mul_adr.sin_addr.s_addr = inet_addr(argv[1]);
    mul_adr.sin_port = htons(atoi(argv[2]));

    //設置生存時間(除了這裏其它基本和UDP編寫同樣)
    //setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time_live, sizeof(time_live));

    /*add:廣播修改處*/
    //默認套接字是關閉廣播的,開啓以下:
    int so_brd = 1;  //設置爲1就能夠開啓廣播
    setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void *)&so_brd, sizeof(so_brd));

    if((fp = fopen("/Users/app05/Desktop/test.txt", "r")) == NULL)
        error_handling("fopen() error");

    while (!feof(fp)) //若是文件結束,則返回非0值,不然返回0
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&mul_adr, sizeof(mul_adr));
        sleep(1); //只是爲了加個傳輸數據時間間隔,沒有特殊意義
    }

    fclose(fp);
    close(send_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

 

另外一個修改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, const char * argv[]) {
    int recv_sock;
    int str_len;
    char buf[BUF_SIZE];
    struct sockaddr_in adr;
    //struct ip_mreq join_adr; //多播組結構體

    if(argc != 2)
    {
        printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
        exit(1);
    }

    recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&adr, 0, sizeof(adr));
    adr.sin_family = AF_INET;
    adr.sin_addr.s_addr = htonl(INADDR_ANY);
    adr.sin_port = htons(atoi(argv[1]));

    if(bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)
        error_handling("bind() error");

    //加入多播組
    //join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]);
    //join_adr.imr_interface.s_addr = htonl(INADDR_ANY);
    //setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));

    while (1) {
        str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0);//只須要多播組IP地址,不關心本身主機地址
        if(str_len < 0)
            break;
        buf[str_len] = 0;
        fputs(buf, stdout);
    }

    close(recv_sock);
    return 0;
}


void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

 

 

 

三.多播與廣播的區別

  • 多播:「多播」也能夠稱爲「組播」,在網絡技術的應用並非不少,網上視頻會議、網上視頻點播特別適合採用多播方式。由於若是採用單播方式,逐個節點傳輸,有多少個目標節點,就會有多少次傳送過程,這種方式顯然效率極低,是不可取的;若是採用不區分目標、所有發送的廣播方式,雖然一次能夠傳送完數據,可是顯然達不到區分特定數據接收對象的目的。採用多播方式,既能夠實現一次傳送全部目標節點的數據,也能夠達到只對特定對象傳送數據的目的。   IP網絡的多播通常經過多播IP地址來實現。多播IP地址就是D類IP地址,即224.0.0.0至239.255.255.255之間的IP地址。Windows 2000中的DHCP管理器支持多播IP地址的自動分配。

 

  • 廣播:「廣播」在網絡中的應用較多,如客戶機經過DHCP自動得到IP地址的過程就是經過廣播來實現的。可是同單播和多播相比,廣播幾乎佔用了子網內網絡的全部帶寬。拿開會打一個比方吧,在會場上只能有一我的發言,想象一下若是全部的人同時都用麥克風發言,那會場上就會亂成一鍋粥。集線器因爲其工做原理決定了不可能過濾廣播風暴,通常的交換機也沒有這一功能,不過如今有的網絡交換機(如全向的QS系列交換機)也有過濾廣播風暴功能了,路由器自己就有隔離廣播風暴的做用。   廣播風暴不能徹底杜絕,可是隻能在同一子網內傳播,就好像喇叭的聲音只能在同一會場內傳播同樣,所以在由幾百臺甚至上千臺電腦構成的大中型局域網中,通常進行子網劃分,就像將一個大廳用牆壁隔離成許多小廳同樣,以達到隔離廣播風暴的目的。   在IP網絡中,廣播地址用IP地址「255.255.255.255」來表示,這個IP地址表明同一子網內全部的IP地址。
     
     
     
  •  最後說一句啦。本網絡編程入門系列博客是連載學習的,有興趣的能夠看我博客其餘篇。。。。c++ 網絡編程課設入門超詳細教程 ---目錄

     

    好了今天對網絡編程的學習就到這裏結束了,小飛機我要撤了去吃飯了。,,,不少人大學都很迷茫不知道學點什麼好,,,,,管他的,想那麼多幹嗎,先學了再說,對技術若有偏見,那麼你的領域就侷限於此了---《一專多精》

     

     

     

     

    參考博客:https://blog.csdn.net/u010223072/article/details/48269213

    參考書籍:《TCP/IP 網絡編程 --尹聖雨》

  • 如有興趣交流分享技術,可關注本人公衆號,裏面會不按期的分享各類編程教程,和共享源碼,諸如研究分享關於c/c++,python,前端,後端,opencv,halcon,opengl,機器學習深度學習之類有關於基礎編程,圖像處理和機器視覺開發的知識

相關文章
相關標籤/搜索