前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >广播与组播

广播与组播

作者头像
mindtechnist
发布2024-08-08 17:21:08
690
发布2024-08-08 17:21:08
举报
文章被收录于专栏:机器和智能

首先需要明确的是,广播和组播都是UDP的属性,在TCP中是没有的。

1. 广播

广播的例子随处可见,比如说把屏幕共享给很多人,其实也是广播,首先把屏幕截图,然后广播给所有的客户端,比如说屏幕共享软件,一般都有一个广播地址,只要在同一个网段的客户端都能收到广播,如果设置广播地址为255.255.255.255,那么不管哪个网段都能收到广播。屏幕共享软件会把当前屏幕截图并分为很多小块,然后压缩,广播给所有客户端,客户端再进行解压。

广播的工作过程:

- 服务器

- - 创建套接字 —— socket

- fd绑定服务器IP和端口

- 初始化客户端IP和端口信息

- - struct sockaddr_in cli;

- cli.sin_family = af_inet;

- cli.port = htons(9898);

- inet_pton(af_inet, "xxx.xxx.123.255", &cli.adr);

- - 发送数据:sendto()

- 设置广播权限(给服务器,server虽然设置了广播地址,但是默认是没有广播权限的)

- setsockopt();

- 客户端

- - 创建套接字

- - 显式绑定IP和端口

- - bind();

- - 接收数据 —— server数据

- - recvform();

- 适用范围

- - 只适用于局域网

server只发数据(主动),client只收数据(被动)。不管client想不想接收,server都会发,只要client在server的发送范围内(局域网),就必须收。UDP发送数据需要client的IP和port,而每个client都有自己的不同的IP,所以server需要一个广播地址,只要把数据发送到这个广播地址,所有在同一网段的client都可以收到,同时需要绑定一个固定端口。如果是同一台主机测试广播的话,server和client应该用不同的端口(一个端口只能给一个进程用),如果server和client是不同的主机,那就无所谓了。

2. 组播

组播也叫做多播,组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。

- 组播的适用范围

- 局域网

- Internet —— 广域网

- 组播地址

- - 224.0.0.0~224.0.0.255 —— 预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用。

- 224.0.1.0~224.0.1.255 —— 公用组播地址,可以用于Internet,想要使用需申请。

- 224.0.2.0~238.255.255.255 —— 用户可用的组播地址(临时组地址),全网范围内有效。

- 239.0.0.0~239.255.255.255 —— 本地管理组播地址,仅在特定的本地范围内有效。

- 两个结构体

代码语言:javascript
复制
 struct ip_mreqn
  {
    // 组播组的IP地址,即组播地址。
      struct   in_addr imr_multiaddr; 
      // 本地某一网络设备接口的IP地址。
      struct   in_addr imr_interface; //设置 0.0.0.0 自动适配本机IP   
    int     imr_ifindex; // 网卡编号
  };
  struct in_addr 
  {
    in_addr_t s_addr;
  };

使用函数可以通过网卡名字获取网卡编号

代码语言:javascript
复制
unsigned if_nametoindex(const char *ifname); //根据网卡名字获取网卡编号

组播示意图如下:

server指定一个组播地址,并向组播地址发送数据,client要想接收数据就要加入这个组播地址。

server

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define CLIENT_PORT 9000
#define MAXLINE 1500
#define GROUP "239.0.0.2"

int main(void)
{
  int sockfd, i ;
  struct sockaddr_in serveraddr, clientaddr;
  char buf[MAXLINE] = "itcast\n";
  char ipstr[INET_ADDRSTRLEN]; /* 16 Bytes */
  socklen_t clientlen;
  ssize_t len;
  struct ip_mreqn group;

  /* 构造用于UDP通信的套接字 */
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);

  bzero(&serveraddr, sizeof(serveraddr));
  serveraddr.sin_family = AF_INET; /* IPv4 */
  serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* 本地任意IP INADDR_ANY = 0 */
  serveraddr.sin_port = htons(SERVER_PORT);

  bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

  /*设置组地址*/
  inet_pton(AF_INET, GROUP, &group.imr_multiaddr);
  /*本地任意IP*/
  inet_pton(AF_INET, "0.0.0.0", &group.imr_address);
  /* eth0 --> 编号 命令:ip ad */
  group.imr_ifindex = if_nametoindex("eth0");
  setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &group, sizeof(group));

  /*构造 client 地址 IP+端口 */
  bzero(&clientaddr, sizeof(clientaddr));
  clientaddr.sin_family = AF_INET; /* IPv4 */
  inet_pton(AF_INET, GROUP, &clientaddr.sin_addr.s_addr);
  clientaddr.sin_port = htons(CLIENT_PORT);

  while (1) {
    //fgets(buf, sizeof(buf), stdin);
    sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
    sleep(1);
  }
  close(sockfd);
  return 0;
}

client

代码语言:javascript
复制
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define MAXLINE 4096
#define CLIENT_PORT 9000
#define GROUP "239.0.0.2"

int main(int argc, char *argv[])
{
  struct sockaddr_in serveraddr, localaddr;
  int confd;
  ssize_t len;
  char buf[MAXLINE];

  /* 定义组播结构体 */
  struct ip_mreqn group;
  confd = socket(AF_INET, SOCK_DGRAM, 0);

  //初始化本地端地址
  bzero(&localaddr, sizeof(localaddr));
  localaddr.sin_family = AF_INET;
  inet_pton(AF_INET, "0.0.0.0" , &localaddr.sin_addr.s_addr);
  localaddr.sin_port = htons(CLIENT_PORT);

  bind(confd, (struct sockaddr *)&localaddr, sizeof(localaddr));

  /*设置组地址*/
  inet_pton(AF_INET, GROUP, &group.imr_multiaddr);
  /*本地任意IP*/
  inet_pton(AF_INET, "0.0.0.0", &group.imr_address);
  /* eth0 --> 编号 命令:ip ad */
  group.imr_ifindex = if_nametoindex("eth0");
  /*设置client 加入多播组 */
  setsockopt(confd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));

  while (1) {
    len = recvfrom(confd, buf, sizeof(buf), 0, NULL, 0);
    write(STDOUT_FILENO, buf, len);
  }
  close(confd);
  return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器和智能 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档