广播与组播

广播

  前面我们所写的所有代码都只能实现点对点的通信,除非使用多线程或多进程的手段来实现一对多的通信效果。如何不使用进程线程的手段来实现给局域网中所有的主机发送一对多的广播效果呢?可以使用广播机制。
  特点:
  1.不需要循环给每一个主机发送数据,而是在同一个局域网中所有的主机都能收到广播信息, 只需要向广播地址发送数据即可,整个局域网中的主机都能收到该信息;
  2.只有UDP协议才支持这个操作。
  思路:
  1.由于Linux 下创建的套接字默认是没有打开广播功能的,所以需要手动开启;
  2.创建UDP套接字;
  3.设置广播属性;
  4.往广播地址发送数据即可。

实验代码:向广播地址发送数据

bc_server.c

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

int main(int argc, char const *argv[])
{
   int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
   if (sockfd == -1)
   {
       perror("socker error");
       return -1;
   }
   printf("Socket created successfully\n");

   struct sockaddr_in server_addr;
   int addrlen = sizeof(server_addr);
   bzero(&server_addr, addrlen);


    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(65111);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

   int ret_val = bind(sockfd, (struct sockaddr *)&server_addr, addrlen);
   if (-1 == ret_val)
   {
       perror("bind error");
       return -1;
   }
   printf("bind successfully\n");

   struct sockaddr_in from_addr;
   char *msg = calloc(1, 1024);
   while (1)
   {
       bzero(msg, 1024);
       ret_val = recvfrom(sockfd, msg, 1024, 0, (struct sockaddr *)&from_addr, &addrlen);
       if (ret_val > 0)
       {
            printf("ip:%s port:%d receive a message:%s", 
                inet_ntoa(from_addr.sin_addr),
                ntohs(from_addr.sin_port), 
                msg);
       }
   }
   
   close(sockfd);
   return 0;
}

bc_client.c

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

int main(int argc, char const *argv[])
{
    int ret_val;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
       perror("socker error");
       return -1;
    }
    printf("Socket created successfully\n");

    struct sockaddr_in server_addr;
    int addrlen = sizeof(server_addr);
    bzero(&server_addr, addrlen);
    
    int on = 1;
    ret_val = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
    if (-1 == ret_val)
    {
        perror("setsockopt error");
    }
    
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(65111);
    server_addr.sin_addr.s_addr = inet_addr("192.168.120.255");

    
    char *msg = calloc(1, 1024);
    while (1)
    {
        bzero(msg, 1024);
        fgets(msg, 1024, stdin);
        ret_val = sendto(sockfd, msg, 1024, 0, (struct sockaddr *)&server_addr, addrlen);
        if (ret_val > 0)
        {
            printf("ip:%s port:%d send a message:%s", 
                inet_ntoa(server_addr.sin_addr),
                ntohs(server_addr.sin_port), 
                msg);
        }
        perror("sendto");
    }
    close(sockfd);
    return 0;
}

组播

  组播是处于单播与广播之间的折中选择,在一个局域网内,把某些主机加入到多播组中,并设置一个地址给多播组,这样我们就只需要把数据往该多播组的地址上发送即可,加入该组的所有主机都会收到数据。
  特点:
  1.广播方式发给所有的主机是,如果有太多的数据占用网络带宽,将很容易造成网络风暴影响通信;
  2.在组播前必须为多播组设置一个IP地址,该IP地址必须是D类网络地址(组播地址);
  3.只有UDP协议支持组播功能。

网络地址分类

网络字节 主机字节 范围
A类地址: 1字节 3字节 1.0.0.1 --- 126.255.255.255
B类地址: 2字节 2字节 128.0.0.1 --- 191.255.255.255
C类地址: 3字节 1字节 192.0.0.1 --- 223.255.255.255
D类地址: 不区分 不区分 224.0.0.1 --- 239.255.255.255
E类地址: 地址保留,仅作实验和开发用 240.0.0.0 --- 255.255.255.255

关键代码

struct ip_mreq v; //定义一个组播结构体
bzero(&v,sizeof(v));

inet_pton(AF_INET,"224.0.0.100",&v.imr_multiaddr);//多播组的IP地址
inet_pton(AF_INET,"192.168.100.2",&v.imr_interface);//服务器的IP地址

//加入组播属性
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&v,sizeof(v));
posted @ 2021-01-20 00:01  ding-ding-light  阅读(184)  评论(0编辑  收藏  举报