网络编程之udp学习之udp的多播(组播)和广播案例03

概述,关于多播,广播这些我Qt相关的文章 也有讲述过。

https://blog.csdn.net/weixin_44517656/article/details/105950817	//ip相关知识
https://blog.csdn.net/weixin_44517656/article/details/105959683	//多播与广播
https://blog.csdn.net/weixin_44517656/article/details/105970733	//qt实现广播与组播案例

1 多播(组播)

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

224.0.0.0224.0.0.255		为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
224.0.1.0224.0.1.255		是公用组播地址,可以用于Internet;欲使用需申请。
224.0.2.0238.255.255.255	为用户可用的组播地址(临时组地址),全网范围内有效;
239.0.0.0239.255.255.255	为本地管理组播地址,仅在特定的本地范围内有效。

可使用ip ad命令查看网卡编号:
在这里插入图片描述
if_nametoindex 命令可以根据网卡名,获取网卡序号。由于我赖得安装所以没有测试。

1.2 案例
组播在linux的情况就是:服务器需要将组播地址赋值给组播权限struct ip_mreqn group结构体,然后再给客户端赋值多一次组播地址即可。而客户端只需要加入一次组播地址即可。
这就相当于每个用户自己绑定一次自己的ip和端口后(服务器端口为私有,客户端端口为组播端口),然后利用setsockopt函数加入组播地址即可。例如我们的qq群,微信群。
server.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define MAXLINE 1500

#define GROUP "239.0.0.2"	/* 组播地址 */
//#define GROUP "224.0.0.2"	/* 组播地址 */
#define CLIENT_PORT 9000	/* 客户端需要加入的组播端口 */

// struct ip_mreqn {
// 		struct in_addr	imr_multiaddr;			/* IP multicast address of group */
// 		struct in_addr	imr_address;			/* local IP address of interface */
// 		int 			imr_ifindex;			/* Interface index */
// };

int main(void)
{
    int sockfd;
    struct sockaddr_in serveraddr, clientaddr;
    char buf[MAXLINE] = {0};
    struct ip_mreqn group;

	/* 初始化 */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);                /* 网络(tcp,udp)参1都是使用AF_INET,参2使用SOCK_STREAM或者SOCK_DGRAM,tcp一般前者,udp后者 */
    if (sockfd < 0){      
        printf ("socket error\n");     
        exit (1);   
    }
    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);
	if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){      
        printf ("bind error\n");     
        exit (1);   
    }

	/* 设置组播地址IP_MULTICAST_IF和组播权限struct ip_mreqn group */
    inet_pton(AF_INET, GROUP, &group.imr_multiaddr);        /* 设置组地址 */
    inet_pton(AF_INET, "0.0.0.0", &group.imr_address);      /* 本地任意IP */
    group.imr_ifindex = if_nametoindex("eth0");             /* 给出网卡名,转换为对应编号: eth0 --> 编号  命令:ip ad */
    setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &group, sizeof(group));  
	
	/* 构造 client 地址 IP+端口。 IPv4,239.0.0.2+9000 */
    bzero(&clientaddr, sizeof(clientaddr));                 
    clientaddr.sin_family = AF_INET;
    inet_pton(AF_INET, GROUP, &clientaddr.sin_addr.s_addr);
    clientaddr.sin_port = htons(CLIENT_PORT);

    int i = 0;
    while (1) {
        memset(buf, 0x00, MAXLINE);
        sprintf(buf, "itcast %d", i++);
        printf("%s\n", buf);
        //fgets(buf, sizeof(buf), stdin);
        sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
        sleep(1);
    }

    close(sockfd);

    return 0;
}

client.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 6666

#define GROUP "239.0.0.2"	/* 组播地址,需要和服务器保持一致 */
//#define GROUP "224.0.0.2"	/* 组播地址,需要和服务器保持一致 */
#define CLIENT_PORT 9000	/* 客户端需要加入的组播端口 */

int main(int argc, char *argv[])
{
    struct sockaddr_in localaddr;
    int confd;
    ssize_t len;
    char buf[BUFSIZ];
    struct ip_mreqn group;                                                  /* 组播结构体 */

	/* 初始化 */
    confd = socket(AF_INET, SOCK_DGRAM, 0);
    if (confd < 0){      
        printf ("socket error\n");     
        return -1;   
    }
    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);
    if (bind(confd, (struct sockaddr *)&localaddr, sizeof(localaddr)) < 0){      
        printf ("bind error\n");     
        return -1;      
    }

	/* 设置client加入多播组IP_ADD_MEMBERSHIP */
    inet_pton(AF_INET, GROUP, &group.imr_multiaddr);                        /* 设置组地址 */
    inet_pton(AF_INET, "0.0.0.0", &group.imr_address);                      /* 使用本地任意IP添加到组播组 */
    group.imr_ifindex = if_nametoindex("eth0");                             /* 通过网卡名-->编号 ip ad */
    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;
}

2 广播

server.c

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

#define SERVER_PORT 8000                                    /* 无关紧要 */
#define MAXLINE 1500
//#define BROADCAST_IP "192.168.42.255"						/* 广播地址 */
#define BROADCAST_IP "255.255.255.255"						/* 广播地址 */
#define CLIENT_PORT 9000                                    /* 广播端口(重要) */

int main(void)
{
    int sockfd;
    struct sockaddr_in serveraddr, clientaddr;
    char buf[MAXLINE];

    /* 构造用于UDP通信的套接字 */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);				/* 网络(tcp,udp)参1都是使用AF_INET,参2使用SOCK_STREAM或者SOCK_DGRAM,tcp一般前者,udp后者 */
    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));

	/* 设置广播SO_BROADCAST */
    int flag = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));

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

    int i = 0;
    while (1) {
        //sprintf(buf, "Drink %d glasses of water\n", i++);
        memset(buf, 0x00, MAXLINE);
        sprintf(buf, "Drink %d glasses of water", i++);
        printf("%s\n", buf);
        //fgets(buf, sizeof(buf), stdin);
        sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
        sleep(1);
    }
    close(sockfd);
    return 0;
}

client.c

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

#define SERVER_PORT 8000
#define MAXLINE 4096
#define CLIENT_PORT 9000

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

    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);
    int ret = bind(confd, (struct sockaddr *)&localaddr, sizeof(localaddr));  //显示绑定不能省略
    if (ret < 0)
        printf("...bind error...\n");

    while (1) {
        printf("len=%d\n", len);
        len = recvfrom(confd, buf, sizeof(buf), 0, NULL, 0);
        printf("len=%d\n", len);
        write(STDOUT_FILENO, buf, len);
    }
    close(confd);

    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值