• 网络编程04-UDP的广播、组播


    目录

    一、UDP广播通信

    1、什么是广播

    2、特点

    3、广播地址

    4、实现广播的过程(一定是使用UDP协议)

    广播发送端

    广播接收方

    练习1: 把广播通信进行实现

    发送端

    接收端

    二、UDP组播(群聊)

    1、概念

    2、组播特点

    3、IP地址分类

    特殊地址 

    4、接收端怎么接收组播消息? -->需要加入组播属性的套接字 

    5、组播通信的过程

    发送端

    接收端

    发送端

    接收端


    一、UDP广播通信

    1、什么是广播

    单播:数据包发送方式只有一个接受方
    广播:同时发给局域网中的所有主机

    2、特点

    只有用户数据报套接字(使用UDP协议)才能广播

    3、广播地址

    以192.168.63.0网段为例: . .***.255 代表该网段的广播地址。发送给该地址的数据包被所有主机接收
    比如我们当前教室的局域网段 是 192.168.63.0 ,那么广播地址就是 192.168.63.255
    sendto("你好",192.168.14.255);

    4、实现广播的过程(一定是使用UDP协议)

     

    广播发送端

    1、创建数据报套接字 UDP
    int socketfd = socket(AF_INET,SOCK_DGRAM,0);
    2、设置socketfd套接字文件描述符的属性为 广播 。(也就是允许发送广播数据包SO_BROADCAST -----》使用广播方式传送
    1. int on=1;
    2. setsockopt(sockfd , SOL_SOCKET,SO_BROADCAST,&on, sizeof(on));
    3、发送数据 ,指定接收方为广播地址
    1. struct sockaddr_in sendAddr;
    2. sendAddr.sin_family = AF_INET;
    3. sendAddr.sin_port = htons(10000);
    4. sendAddr.sin_addr.s_addr = inet_addr("192.168.14.255");//一定是广播地址,广播发送
    5. sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&sendAddr,sizeof(sendAddr));
    4、关闭
    close();

    广播接收方

    1、创建用户数据报套接字
    int socketfd = socket(AF_INET,SOCK_DGRAM,0);
    2、绑定(192.168.14.255)广播IP地址和端口号 (10000)
    注意:绑定的端口必须和发送方指定的端口相同
    1. struct sockaddr_in ownAddr;
    2. ownAddr.sin_family = AF_INET;
    3. ownAddr.sin_port = htons(10000);
    4. //uint32_t htonl(uint32_t hostlong); 将 主机IP转为 网络IP
    5. ownAddr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY(0.0.0.0) 代表本机所有的地址
    6. //inet_addr("192.168.63.255");
    3、接收数据
    recvfrom();
    4、关闭
    close();

    练习1: 把广播通信进行实现

    发送端

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <string.h>
    4. #include <sys/types.h> /* See NOTES */
    5. #include <sys/socket.h>
    6. #include <sys/socket.h>
    7. #include <netinet/in.h>
    8. #include <arpa/inet.h>
    9. #define GUANG_IP "192.168.11.255"
    10. #define GUANG_PORT 60001
    11. int main()
    12. {
    13. //建立套接字
    14. int socket_fd = socket(AF_INET,SOCK_DGRAM,0);
    15. if(socket_fd < 0)
    16. {
    17. perror("sokcet fail");
    18. return -1;
    19. }
    20. //设置广播属性
    21. int on=1;
    22. setsockopt(socket_fd , SOL_SOCKET,SO_BROADCAST,&on, sizeof(on));
    23. //给广播地址发送数据
    24. struct sockaddr_in send_addr;
    25. send_addr.sin_family = AF_INET;
    26. send_addr.sin_port = htons(GUANG_PORT);
    27. send_addr.sin_addr.s_addr = inet_addr(GUANG_IP);//广播地址
    28. char buf[1024] = {0};
    29. while(1)
    30. {
    31. bzero(buf,sizeof(buf));
    32. scanf("%s",buf);
    33. //发送的是实际的长度
    34. sendto(socket_fd,buf,strlen(buf),0,(struct sockaddr *)&send_addr,sizeof(send_addr));
    35. }
    36. //关闭套接字
    37. close(socket_fd);
    38. }

    接收端

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <string.h>
    4. #include <sys/types.h> /* See NOTES */
    5. #include <sys/socket.h>
    6. #include <sys/socket.h>
    7. #include <netinet/in.h>
    8. #include <arpa/inet.h>
    9. #define GUANG_IP "192.168.11.255"
    10. #define GUANG_PORT 60001
    11. int main()
    12. {
    13. //建立套接字
    14. int socket_fd = socket(AF_INET,SOCK_DGRAM,0);
    15. if(socket_fd < 0)
    16. {
    17. perror("sokcet fail");
    18. return -1;
    19. }
    20. //绑定广播地址
    21. struct sockaddr_in my_addr;
    22. my_addr.sin_family = AF_INET;
    23. my_addr.sin_port = htons(GUANG_PORT);
    24. my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY本机任意IP地址--常用方法
    25. //send_addr.sin_addr.s_addr = inet_addr(GUANG_IP);//广播地址
    26. bind(socket_fd,(struct sockaddr *)&my_addr,sizeof(my_addr));
    27. char buf[1024] = {0};
    28. int ret;
    29. struct sockaddr_in recv_addr;
    30. socklen_t addrlen = sizeof(recv_addr);
    31. while(1)
    32. {
    33. bzero(buf,sizeof(buf));//清空缓冲区
    34. ret = recvfrom(socket_fd,buf,sizeof(buf),0,(struct sockaddr *)&recv_addr,&addrlen);
    35. char *ip = inet_ntoa(recv_addr.sin_addr);
    36. int port = ntohs(recv_addr.sin_port);
    37. printf("[ip:%s port:%d] buf:%s ret:%d\n",ip,port,buf,ret);
    38. }
    39. //关闭套接字
    40. close(socket_fd);
    41. }

    二、UDP组播(群聊)

    1、概念

    组播是介于单播与广播之间,在一个局域网内,将某些主机添加到组中,并设置一个组地址.我们
    只需要将数据发送到组播地址即可,加入到该组的所有主机都能接收到数据

    2、组播特点

            需要给组播设置IP 地址,该 IP 必须是 D 类地址
            只有UDP 才能设置组播

    3、IP地址分类

    IP地址 = 网络号 + 主机号

     

    特殊地址 

    4、接收端怎么接收组播消息? -->需要加入组播属性的套接字 

    1. #define IP_ADD_MEMBERSHIP 加入组播
    2. // usr/include/linux/in.h
    3. struct ip_mreq {
    4. struct in_addr imr_multiaddr; /* 多播组的IP地址 224.0.0.10/
    5. struct in_addr imr_interface; /* 需要加入到多组的IP地址 192.168.53.134 */
    6. };

    5、组播通信的过程

     

    发送端

    1、创建UDP数据报套接字
    2、发送数据,往组播地址(224.0.0.10 )里面发送数据
    3、关闭

    接收端

    (要把接收端的IP地址加入到组播里面)
    1、创建UDP数据报套接字
    2、定义组播结构体
    struct ip_mreq vmreq;
    3、设置组播ip(初始化 组播结构体)
    1. inet_pton(AF_INET,"224.0.0.10",&vmreq.imr_multiaddr); // 组播地址
    2. inet_pton(AF_INET,"192.168.63.2",&vmreq.imr_interface); // 需要添加到组的ip
    3. #ininclude <arpa/inet.h>
    4. int inet_pton(int af, const char *src, void *dst);
    参数:
            af : 你要选择哪一种协议族 IPV4 --》AF_INET 还是 IPV6--》AF_INET6
            src:本地IP地址
            dst:将本地IP地址转为网络IP地址存储到这里
    作用:
            将本地IP地址转为网络IP地址
     4、加入组播属性(也就是设置这个套接字 可以接收组播信息)
    setsockopt(socketfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&vmreq,sizeof(vmreq));
     5、绑定地址
    1. struct sockaddr_in saddr;
    2. saddr.sin_family = AF_INET;
    3. saddr.sin_port = htons(atoi(argv[1]));
    4. saddr.sin_addr.s_addr = htonl(INADDR_ANY); //htonl(INADDR_ANY) 代表 主机所有的地址
    5. bind(socketfd,(struct sockaddr *)&saddr,sizeof(saddr));

     6、接收数据

     recvfrom(......)

    发送端

    1. #include <stdio.h>
    2. #include <string.h>
    3. #include <unistd.h>
    4. #include <sys/types.h> /* See NOTES */
    5. #include <sys/socket.h>
    6. #include <netinet/in.h>
    7. #include <arpa/inet.h>
    8. /*
    9. *发送端
    10. */
    11. #define GROUP_IP "224.0.0.10"
    12. #define GROUP_PORT 60002
    13. int main()
    14. {
    15. //建立套接字
    16. int socket_fd;
    17. socket_fd = socket(AF_INET,SOCK_DGRAM,0);
    18. if(socket_fd < 0)
    19. {
    20. perror("socket fail");
    21. return -1;
    22. }
    23. //往组播地址发送数据
    24. struct sockaddr_in send_addr;
    25. send_addr.sin_family = AF_INET;
    26. send_addr.sin_port = htons(GROUP_PORT);
    27. send_addr.sin_addr.s_addr = inet_addr(GROUP_IP);
    28. bind(socket_fd,(struct sockaddr *)&send_addr,sizeof(send_addr));
    29. //往组播地址发送数据
    30. char buf[1024] = {0};
    31. int ret;
    32. while(1)
    33. {
    34. bzero(buf,sizeof(buf));
    35. scanf("%s",buf);
    36. sendto(socket_fd,buf,strlen(buf),0,(struct sockaddr *)&send_addr,sizeof(send_addr));
    37. }
    38. //关闭套接字
    39. close(socket_fd);
    40. }

    接收端

    1. #include <stdio.h>
    2. #include <string.h>
    3. #include <unistd.h>
    4. #include <sys/types.h> /* See NOTES */
    5. #include <sys/socket.h>
    6. #include <netinet/in.h>
    7. #include <arpa/inet.h>
    8. /*
    9. * 接收端
    10. */
    11. #define GROUP_IP "224.0.0.10"
    12. #define GROUP_PORT 60002
    13. int main()
    14. {
    15. //建立套接字
    16. int socket_fd;
    17. socket_fd = socket(AF_INET,SOCK_DGRAM,0);
    18. if(socket_fd < 0)
    19. {
    20. perror("socket fail");
    21. return -1;
    22. }
    23. //定义组播结构体
    24. struct ip_mreq vmreq;
    25. //添加组播地址
    26. inet_pton(AF_INET,"224.0.0.10",&vmreq.imr_multiaddr);
    27. //将自己的ip添加到到组播地址中
    28. inet_pton(AF_INET,"192.168.11.2",&vmreq.imr_interface);
    29. //设置组播属性到套接字中
    30. setsockopt(socket_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&vmreq,sizeof(vmreq));
    31. //绑定本机任意地址
    32. struct sockaddr_in saddr;
    33. saddr.sin_family = AF_INET;
    34. saddr.sin_port = htons(60002);
    35. saddr.sin_addr.s_addr = htonl(INADDR_ANY); //htonl(INADDR_ANY) 代表 主机所有的地址
    36. bind(socket_fd,(struct sockaddr *)&saddr,sizeof(saddr));
    37. //接收数据
    38. struct sockaddr_in recv_addr;
    39. socklen_t addrlen = sizeof(recv_addr);
    40. char buf[1024] = {0};
    41. int ret;
    42. while(1)
    43. {
    44. memset(buf,0,sizeof(buf));
    45. ret = recvfrom(socket_fd,buf,sizeof(buf),0,(struct sockaddr *)&recv_addr,&addrlen);
    46. char *ip = inet_ntoa(recv_addr.sin_addr);
    47. int port = ntohs(recv_addr.sin_port);
    48. printf("[ip:%s port:%d] buf:%s ret:%d\n",ip,port,buf,ret);
    49. }
    50. //关闭套接字
    51. close(socket_fd);
    52. }

  • 相关阅读:
    [Android]Android P(9) WIFI学习笔记 - 扫描 (3)
    C++ :输出 Hello, World
    JVM堆和方法区是怎样的关系?
    搭建Mysql主从复制
    Git构建分布式版本控制系统
    css实现风车效果
    Linux基本指令——综合操作
    【Java Web】用Redis优化登陆模块
    快速核对两个表格数据
    超实用!win10网页录屏的3种方法
  • 原文地址:https://blog.csdn.net/weixin_48102054/article/details/127736689