UDP组播通信

组播IP地址: D类IP地址  1110.**********  224.0.0.1 ~ 239.255.255.255

组播MAC地址:低23位,直接对应IP地址, 从右数第24位为0, 前24位为 01:00:5E

最终数据帧如图

局域网所有主机网卡都会收到这一消息,但是只有加入到组内的主机才接受该数据包。组播不影响同一局域网内其他主机的效率

将自己的主机IP地址加入到组播地址组:

  1. setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq));

第四个参数的类型如下:

  1. struct ip_mreqn
  2. {
  3. struct in_addr imr_multiaddr; //组播地址
  4. struct in_addr imr_address; //自己IP地址
  5. };

加入相应的组后,即可接收对应组播地址的数据包了

例子:

发送端:发送组播消息 绑定了自己的ip  没有加入组 只是说发送到某个组

接收端:加入了正确的组,则可以接收到;没有加入相应的组,则不能接收到

用到了新的函数

gethostbyname

  1. #include<netdb.h>
  2. struct hostent* gethostbyname(const char* hostname);

返回值类型

  1. struct hostent{
  2.   char * h_name;
  3.   char ** h_aliases;
  4.   short h_addrtype;
  5.   short h_length;
  6.   char ** h_addr_list;
  7. };
  8. #define h_addr h_addr_list[0]

bcopy

  1. void bcopy(const void *src, void *dest, int n);

发送端代码:

  1. #include<sys/types.h>
  2. #include<sys/socket.h>
  3. #include<arpa/inet.h>
  4. #include<stdio.h>
  5. #include<stdlib.h>
  6. #include<string.h>
  7. #define BUFLEN 255
  8.  
  9. int main(int argc, char **argv)
  10. {
  11. struct sockaddr_in peeraddr, myaddr;
  12. int sockfd;
  13. char recmsg[BUFLEN + ];
  14. unsigned int socklen;
  15. //以UDP方式创建SOCKET对象
  16. sockfd = socket(AF_INET, SOCK_DGRAM, );
  17. if(sockfd < )
  18. {
  19. printf("socket creating error\n");
  20. exit(EXIT_FAILURE);
  21. }
  22. socklen = sizeof(struct sockaddr_in);
  23. memset(&peeraddr, , socklen);
  24. peeraddr.sin_family = AF_INET;
  25. peeraddr.sin_port = htons();
  26. if(argv[]) //参数1 获取组播地址
  27. {
  28. if(inet_pton(AF_INET, argv[], &peeraddr.sin_addr) <= )
  29. {
  30. printf("wrong group address!\n");
  31. exit(EXIT_FAILURE);
  32. }
  33. }
  34. else
  35. {
  36. printf("no group address!\n");
  37. exit(EXIT_FAILURE);
  38. }
  39. memset(&myaddr, , socklen);
  40. myaddr.sin_family = AF_INET;
  41. myaddr.sin_port = htons();
  42. if(argv[]) //参数2 读取本机绑定的IP地址
  43. {
  44. if(inet_pton(AF_INET, argv[], &myaddr.sin_addr) <= )
  45. {
  46. printf("self ip address error!\n");
  47. exit(EXIT_FAILURE);
  48. }
  49. }
  50. else
  51. {
  52. myaddr.sin_addr.s_addr = INADDR_ANY;
  53. }
  54. //绑定
  55. if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) == -)
  56. {
  57. printf("Bind error\n");
  58. exit(EXIT_FAILURE);
  59. }
  60. while()
  61. {
  62. bzero(recmsg, BUFLEN + );
  63. printf("input message to send:");
  64. if(fgets(recmsg, BUFLEN, stdin) == (char *)EOF)
  65. exit(EXIT_FAILURE);
  66. //发送给组播组内主机
  67. if(sendto(sockfd, recmsg, strlen(recmsg), , (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < )
  68. {
  69. printf("sendto error\n");
  70. exit(EXIT_FAILURE);
  71. }
  72. printf("send message:%s\n", recmsg);
  73. }
  74. }

接收端代码

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<sys/types.h>
  6. #include<netinet/in.h>
  7. #include<netinet/tcp.h>
  8. #include<sys/socket.h>
  9. #include<sys/wait.h>
  10. #include<unistd.h>
  11. #include<arpa/inet.h>
  12. #include<sys/time.h>
  13. #include<netdb.h>
  14. #define BUFLEN 255
  15.  
  16. int main(int argc, char **argv)
  17. {
  18. struct sockaddr_in peeraddr;
  19. struct in_addr ia;
  20. int sockfd;
  21. char recmsg[BUFLEN + ];
  22. unsigned int socklen, n;
  23. struct hostent *group;
  24. struct ip_mreq mreq;
  25. //创建socket UDP
  26. sockfd = socket(AF_INET, SOCK_DGRAM, ); //创建UDP方式的socket
  27. if(sockfd < )
  28. {
  29. perror("socket");
  30. exit(EXIT_FAILURE);
  31. }
  32. bzero(&mreq, sizeof(struct ip_mreq));
  33. //从参数1获取组播地址
  34. if(argv[])
  35. {
  36. if((group = gethostbyname(argv[])) == (struct hostent *)) //??
  37. {
  38. perror("gethostbyname");
  39. exit(EXIT_FAILURE);
  40. }
  41. }
  42. else
  43. {
  44. printf("please input a group address: 224.0.0.1 ~ 239.255.255.255\n");
  45. exit(EXIT_FAILURE);
  46. }
  47. bcopy((void *)group->h_addr, (void *)&ia, group->h_length); //??
  48. bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr)); //??
  49. //从参数2中读取本机IP地址
  50. if(argv[])
  51. {
  52. if(inet_pton(AF_INET, argv[], &mreq.imr_interface.s_addr) <= )
  53. {
  54. printf("Wrong dest IP address!\n");
  55. exit(EXIT_FAILURE);
  56. }
  57. }
  58. else
  59. {
  60. printf("Wrong dest IP address!\n");
  61. exit(EXIT_FAILURE);
  62. }
  63.  
  64. //设置客户端加入到组
  65. if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -)
  66. {
  67. perror("setsockopt");
  68. exit(EXIT_FAILURE);
  69. }
  70. //
  71. socklen = sizeof(struct sockaddr_in);
  72. memset(&peeraddr, , socklen);
  73. peeraddr.sin_family = AF_INET;
  74. peeraddr.sin_port = htons();
  75. if(argv[]) //参数1 获取组播地址
  76. {
  77. if(inet_pton(AF_INET, argv[], &peeraddr.sin_addr) <= )
  78. {
  79. printf("wrong group address!\n");
  80. exit(EXIT_FAILURE);
  81. }
  82. }
  83. else
  84. {
  85. printf("no group address!\n");
  86. exit(EXIT_FAILURE);
  87. }
  88. //绑定
  89. if(bind(sockfd, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) == -)
  90. {
  91. printf("Bind error\n");
  92. exit(EXIT_FAILURE);
  93. }
  94. while()
  95. {
  96. bzero(recmsg, BUFLEN + );
  97. n = recvfrom(sockfd, recmsg, BUFLEN, , (struct sockaddr *)&peeraddr, &socklen);
  98. if(n < )
  99. {
  100. printf("recvfrom err in udptalk!\n");
  101. exit(EXIT_FAILURE);
  102. }
  103. else
  104. {
  105. recmsg[n] = ;
  106. printf("peer:%s\n", recmsg);
  107. }
  108. }
  109. }

【linux高级程序设计】(第十五章)UDP网络编程应用 3的更多相关文章

  1. 读书笔记 - js高级程序设计 - 第十五章 使用Canvas绘图

    读书笔记 - js高级程序设计 - 第十三章 事件   canvas 具备绘图能力的2D上下文 及文本API 很多浏览器对WebGL的3D上下文支持还不够好   有时候即使浏览器支持,操作系统如果缺缺 ...

  2. JavaScript高级程序设计:第五章

    引用类型 一.object类型: 创建object实例的方式有两种.第一种是使用new操作符后跟Object构造函数,如下所示: var  person = new  Object(): person ...

  3. 《javascript高级程序设计》第五章 reference types

    第5 章 引用类型5.1 Object 类型5.2 Array 类型 5.2.1 检测数组 5.2.2 转换方法 5.2.3 栈方法 5.2.4 队列方法 5.2.5 重排序方法 5.2.6 操作方法 ...

  4. 【linux高级程序设计】(第九章)进程间通信-管道 1

    Linux操作系统所支持的主要进程间的通信机制. 无名管道 PIPE cat test.txt| grep hello 上面这种管道,将一个命令的输出作为另一个命令的输入,而这种管道是临时的,命令执行 ...

  5. linux高级管理第十二章--rsync

    实验部分 1.安装rsync 2.配置文件 3.配置密码 4.后续 5.为了测试,创建几个文件 配置实时同步 1.调整inotify内核参数 安装inotify-tools 测试同步 编写脚本 验证 ...

  6. 《JAVASCRIPT高级程序设计》第五章(2)

    一.Date类型 Date类型类型用于保存日期,有以下几种创建方式: //获取当前时间 var now = new Date(); //获取当前时间的毫秒数 var nowSecond = Date. ...

  7. 《JAVASCRIPT高级程序设计》第五章(1)

    引用类型是一种将数据和功能组合到一起的数据结构,它与类相似,但是是不同的概念:ECMAScript虽然是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和结构等基本结构.引用类型也被称为“对 ...

  8. Javascript高级程序设计笔记 <第五章> 引用类型

    一.object类型 创建object实例的方式有两种: //第一种使用new操作符跟构造函数 var person= new Object(); person.name="小王" ...

  9. Javascript高级程序设计复习——第五章引用类型 【原创】

    5.1  Object类型 1:创建Object实例的两种方式 ①new构造法 var obj1 = new Object(); 注意大写!不传递参数时可以省略圆括号 obj1.hehe = &quo ...

  10. Linux高级运维 第五章 Vim编辑器和恢复ext4下误删除的文件-Xmanager工具

    5.1  vim主要模式介绍,vim命令模式. 确保系统已经安装了VIM工具 [root@panda ~]# rpm -qf `which vim` [root@panda ~]# rpm -qf ` ...

随机推荐

  1. issubclasss/type/isinstance/callable/super

    issubclass() : 方法用于判断第一个参数是否是第二个参数的子子孙孙类. 语法:issubclass(sub, super) 检查sub类是否是 super 类的派生类 class A: p ...

  2. CSS3 Shape ---使用形状改变旁边内容的布局

    注意 本文所实现的功能,在浏览器的支持上并不好,除chrome浏览器外其余的大部分浏览器均不支持,虽然可以使用polyfill解决,但也不能很好的支持,有时也会出错 polyfill使用方法 下载po ...

  3. 从库函数操作RCC的流程来理解偏移变量

    下面是库函数操作RCC流程,看完后有我的疑问:偏移地址的理解 1,库函数直接操作:RCC库函数操作  RCC_APB2PeriphClockCmd ()RCC->APB2ENR |= RCC_A ...

  4. ElasticSearch学习笔记(四)-- 分布式

    1. 分布式介绍及cerebro cerebro插件 点击release下载 解压运行 访问9000端口,连接es的9200端口 2. 构建集群 新增一个节点 3. 副本与分片 再加入一个节点 4.  ...

  5. mybatis和redis整合 log4j打印sql语句

    首先,需要在项目中引进jedis-2.8.1.jar包,在pom.xml里加上 <dependency> <groupId>redis.clients</groupId& ...

  6. hash算法和常见的hash函数 [转]

       Hash,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值. 这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能 会散列成相同的输出,而不 ...

  7. quick sort去除无用判断

    #include <stdio.h> #include <stdlib.h> //int a[]={1000,10000,9,10,30,20,50,23,90,100,10} ...

  8. MySQL、MongoDB、Redis 数据库之间的区别与使用(本章迭代更新)

    MySQL.MongoDB.Redis 数据库之间的区别与使用 MySQL.MongoDB.Redis 数据库之间的区别与使用(本章迭代更新) update:2019年2月20日 15:21:19(本 ...

  9. Python作业--登录接口

    作业需求: 编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 实现思路: 1.从文件获取用户名密码 2.判断是否在黑名单中 3.验证用户名密码 成功:输出认证成功 错误:判断验证次 ...

  10. ironic baremetal node rescue/unrescue mode

    环境ironic-api ironic-conductor,ironicclient均升级为Queens版本 官网说明API版本为1.38才支持rescue/unrescue,所以修改下openrc文 ...