UDP组播通信

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

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

最终数据帧如图

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

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

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

第四个参数的类型如下:

struct ip_mreqn
{
struct in_addr imr_multiaddr; //组播地址
struct in_addr imr_address; //自己IP地址
};

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

例子:

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

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

用到了新的函数

gethostbyname

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

返回值类型

struct hostent{
  char * h_name;
  char ** h_aliases;
  short h_addrtype;
  short h_length;
  char ** h_addr_list;
};
#define h_addr h_addr_list[0]

bcopy

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

发送端代码:

#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFLEN 255 int main(int argc, char **argv)
{
struct sockaddr_in peeraddr, myaddr;
int sockfd;
char recmsg[BUFLEN + ];
unsigned int socklen;
//以UDP方式创建SOCKET对象
sockfd = socket(AF_INET, SOCK_DGRAM, );
if(sockfd < )
{
printf("socket creating error\n");
exit(EXIT_FAILURE);
}
socklen = sizeof(struct sockaddr_in);
memset(&peeraddr, , socklen);
peeraddr.sin_family = AF_INET;
peeraddr.sin_port = htons();
if(argv[]) //参数1 获取组播地址
{
if(inet_pton(AF_INET, argv[], &peeraddr.sin_addr) <= )
{
printf("wrong group address!\n");
exit(EXIT_FAILURE);
}
}
else
{
printf("no group address!\n");
exit(EXIT_FAILURE);
}
memset(&myaddr, , socklen);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons();
if(argv[]) //参数2 读取本机绑定的IP地址
{
if(inet_pton(AF_INET, argv[], &myaddr.sin_addr) <= )
{
printf("self ip address error!\n");
exit(EXIT_FAILURE);
}
}
else
{
myaddr.sin_addr.s_addr = INADDR_ANY;
}
//绑定
if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) == -)
{
printf("Bind error\n");
exit(EXIT_FAILURE);
}
while()
{
bzero(recmsg, BUFLEN + );
printf("input message to send:");
if(fgets(recmsg, BUFLEN, stdin) == (char *)EOF)
exit(EXIT_FAILURE);
//发送给组播组内主机
if(sendto(sockfd, recmsg, strlen(recmsg), , (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < )
{
printf("sendto error\n");
exit(EXIT_FAILURE);
}
printf("send message:%s\n", recmsg);
}
}

接收端代码

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netinet/tcp.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/time.h>
#include<netdb.h>
#define BUFLEN 255 int main(int argc, char **argv)
{
struct sockaddr_in peeraddr;
struct in_addr ia;
int sockfd;
char recmsg[BUFLEN + ];
unsigned int socklen, n;
struct hostent *group;
struct ip_mreq mreq;
//创建socket UDP
sockfd = socket(AF_INET, SOCK_DGRAM, ); //创建UDP方式的socket
if(sockfd < )
{
perror("socket");
exit(EXIT_FAILURE);
}
bzero(&mreq, sizeof(struct ip_mreq));
//从参数1获取组播地址
if(argv[])
{
if((group = gethostbyname(argv[])) == (struct hostent *)) //??
{
perror("gethostbyname");
exit(EXIT_FAILURE);
}
}
else
{
printf("please input a group address: 224.0.0.1 ~ 239.255.255.255\n");
exit(EXIT_FAILURE);
}
bcopy((void *)group->h_addr, (void *)&ia, group->h_length); //??
bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr)); //??
//从参数2中读取本机IP地址
if(argv[])
{
if(inet_pton(AF_INET, argv[], &mreq.imr_interface.s_addr) <= )
{
printf("Wrong dest IP address!\n");
exit(EXIT_FAILURE);
}
}
else
{
printf("Wrong dest IP address!\n");
exit(EXIT_FAILURE);
} //设置客户端加入到组
if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//
socklen = sizeof(struct sockaddr_in);
memset(&peeraddr, , socklen);
peeraddr.sin_family = AF_INET;
peeraddr.sin_port = htons();
if(argv[]) //参数1 获取组播地址
{
if(inet_pton(AF_INET, argv[], &peeraddr.sin_addr) <= )
{
printf("wrong group address!\n");
exit(EXIT_FAILURE);
}
}
else
{
printf("no group address!\n");
exit(EXIT_FAILURE);
}
//绑定
if(bind(sockfd, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) == -)
{
printf("Bind error\n");
exit(EXIT_FAILURE);
}
while()
{
bzero(recmsg, BUFLEN + );
n = recvfrom(sockfd, recmsg, BUFLEN, , (struct sockaddr *)&peeraddr, &socklen);
if(n < )
{
printf("recvfrom err in udptalk!\n");
exit(EXIT_FAILURE);
}
else
{
recmsg[n] = ;
printf("peer:%s\n", recmsg);
}
}
}

【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. 7 Vue.js实现loading1

    1 2 3 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter ...

  2. Kafka消费分组和分区分配策略

    Kafka消费分组,消息消费原理 同一个消费组里的消费者不能消费同一个分区,不同消费组的消费组可以消费同一个分区 Kafka分区分配策略 在 Kafka 内部存在两种默认的分区分配策略:Range 和 ...

  3. Linux查看程序端口占用

    使用命令: 1.ps -aux | grep 80 2.使用命令:netstat –apn 查看所有的进程和端口使用情况.

  4. Maven学习 (五) Elipse中发布一个Maven项目到Tomcat

    对于maven初学者的我,经常遇到一个问题就是,maven项目创建成功后,本来已经添加了jar的依赖,但是发布到Tomcat中就是没有jar包存在, 启动Tomcat总是报没有找到jar包,可项目结构 ...

  5. 后端接口迁移(从 webapi 到 openapi)前端经验总结

    此文已由作者张磊授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 前情提要 以前用的是 webapi 现在统一切成 openapi,字段结构统统都变了 接入接口 20+,涉及模 ...

  6. apache的/etc/httpd/conf/httpd.conf和/usr/local/apache2/conf/httpd.conf区别

    一.问题 centos系统用yum安装完apache后,重启后有时会失效,然后去网上找资料,发现有的说重启命令是这样的: /etc/init.d/httpd restart 而有的呢,说重启命令应该是 ...

  7. 二叉树 【转】http://blog.csdn.net/sjf0115/article/details/8645991

    //二叉树 #include<iostream> #include<stack> #include<queue> using namespace std; //二叉 ...

  8. C编译器MinGW安装、下载及在notepad++中运行C程序

    一.C编译器MinGW的下载及安装步骤 打开MinGW官网:http://www.mingw.org/ 图一 图二 图三 图四 图五 图六 系统中配置环境变量: 图七 验证是否安装成功: CMD中运行 ...

  9. (原)UE4.20 自定义编辑器 - 基础(一)创建编辑器模块

            @author:白袍小道 前言: 本小文参考了UnrealC++,游戏编辑器(应该都找不到了嘿嘿)等书籍. 引擎基于UnrealEngine4.20版本(由于UnrealC++ 用的是 ...

  10. python与MySQL数据库

    python与MySQL数据库 慕课网连接 我使用的软件:python2.7 + MySQL+ Navicat for MySQL + Atom 注意:你的数据库表格类型的引擎为:InnoDB :字符 ...