UDP-组播,广播

转自:https://www.cnblogs.com/wangzhilei-src/p/15314315.html

UDP是面向非连接的协议,它不与对方建立连接,而是直接把数据报发给对方。UDP无需建立类如三次握手的连接,使得通信效率很高。因此UDP适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景

sendto
int sendto(int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);

返回值:
    成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。
参数说明:
    s: socket描述符;
    buf: UDP数据报缓存区(包含待发送数据);
    len: UDP数据报的长度;
    flags:调用方式标志位(一般设置为0);
    to:  指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);
    tolen:to所指结构体的长度;

recvfrom()
int recvfrom(int s, void *buf, int len, unsigned int flags,struct sockaddr *from, int *fromlen);

返回值:
    成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。
参数:
    s: socket描述符;
    buf: UDP数据报缓存区(包含所接收的数据);
    len: 缓冲区长度。
    flags: 调用操作方式(一般设置为0)。
    from: 指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);
    fromlen:指针,指向from结构体长度值

UDP点对点

udp_server.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>const int SERV_PORT=6000;
const int MAXLINE=2048;void dg_echo(int sockfd,struct sockaddr *pcliaddr,socklen_t clilen)
{int n;socklen_t len;char mesg[MAXLINE];for (;;){len=clilen;if ((n=recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len))<0){perror("recvfrom error");exit(1);}fputs(mesg, stdout);if((n=sendto(sockfd,mesg,n,0,pcliaddr,len))<0){perror("sendto error");exit(1);}}}
int main(int argc,char **argv)
{int sockfd;struct  sockaddr_in servaddr,cliaddr;bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port =htons(SERV_PORT);if ((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){printf("SOCKET ERROR");exit(1);}if (bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))){perror("bind error");exit(1);}dg_echo(sockfd,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
}
udp_client.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>const int SERV_PORT = 6000;const int MAXLINE = 2048;void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen)
{int n;char sendline[MAXLINE], recvline[MAXLINE + 1];while (fgets(sendline, MAXLINE, fp) != NULL){if (sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen) < 0){perror("sendto error");exit(1);}if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0){perror("recvfrom error");exit(1);}recvline[n] = '\0';fputs(recvline, stdout);}
}
int main(int argc, char **argv)
{int sockfd;struct sockaddr_in servaddr;if (argc != 2){perror("usage:tcpcli");exit(1);}//1.创建套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){perror("socket error");exit(1);}//2.设置链接服务器地址结体bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);if ((inet_pton(AF_INET, argv[1], &servaddr.sin_addr)) <= 0){printf("inet_pton error for %s\n", argv[1]);exit(1);}if ((sockfd == socket(AF_INET, SOCK_DGRAM, 0)) < 0){perror("socket error");}dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));exit(0);
}

UDP广播数据包

路由器不转发广播数据包
交换机转发广播数据包
广播只能在一个广播域(局域网)中传播,而不能跨网段传播
arp协议

  • MAC:FF:FF:FF:FF:FF:FF
  • IP:10.0.0.0/8-->10.255.255.255 广播地址
    192.168.199.1/24-->192.168.199.255 广播地址
    192.168.0.1/30-->192.168.0.3(广播地址)(192.168.0.0回环地址)

UDP广播递送规则

  1. 如果未设置BLOADCASE选项不递送
  2. 如果bind端口不匹配不递送该套接口
  3. 必须bind一个广播地址或绑定INADDR_ANY
  4. 如果udp调用了connect那么源地址和源端口不匹配也不递送,否则递送
  5. ifconfig可disable网卡的BROADCAST标志,让其不能接受以太网广播
  6. ioctl的SIOCSIFFLAGS方法去掉接口的标志IFF_BROADCAST,使之不能接受以太网广播。
recv.c#include "../config.h"int main(int argc,char **argv)
{struct sockaddr_in s_addr;struct sockaddr_in c_addr;int sock;socklen_t addr_len;int len;char buff[128];if ((sock=socket(AF_INET,SOCK_DGRAM,0))==-1){perror("socket");exit(EXIT_FAILURE);}else{printf("create socket.\n\r");}bzero(&s_addr,sizeof(s_addr));s_addr.sin_addr.s_addr=INADDR_ANY;s_addr.sin_family=AF_INET;s_addr.sin_port=htons(PORT);if (bind(sock,(struct sockaddr *)&s_addr,sizeof(s_addr))){perror("bind err");exit(EXIT_FAILURE);}elseprintf("bind address to socket.\n\t");addr_len=sizeof(c_addr);while (1){len=recvfrom(sock,buff,sizeof(buff)-1,0,(struct sockaddr *) &c_addr,&addr_len);if (len<0){perror("recvfrom");exit(EXIT_FAILURE);}buff[len]='\0';printf("recive come from %s:%d message:%s\n\r",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port),buff);return 0;}   
}
send.c#include "../config.h"int main(int argc,char **argv)
{struct sockaddr_in s_addr;int sock;int addr_len;int len;char buff[128];int yes;if ((sock=socket(AF_INET,SOCK_DGRAM,0))==-1){perror("socket");exit(EXIT_FAILURE);}elseprintf("create socket.\n\r");//开启广播yes=1;setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&yes,sizeof(yes));s_addr.sin_family=AF_INET;s_addr.sin_port=htons(PORT);if (argv[1])s_addr.sin_addr.s_addr=inet_addr(argv[1]); //广播地址:xxx.xxx.xxx.255/24else{printf("input server ip\n");exit(0);}addr_len=sizeof(s_addr);strcpy(buff,"hello message");len=sendto(sock,buff,strlen(buff),0,(struct sockaddr *) &s_addr,addr_len);if (len<0){printf("\n\rsend error. \n\r");exit(EXIT_FAILURE);}printf("send success\n\r");return 0;
}
./send 192.168.146.255create socket.send success
  • 抓包

UDP组播数据包

视频会议项目

1.能够在组播组中进行传播,并且路由器可以进行组播数据转发
2.组播(多播)使用D类地址,首位前4位1110,认为是多播地址,其它28位是多播的组编号
3.224.0.0.0~239.255.255.255范围 224.0.0.0~224.0.0.255不需要路由控制
4.所有主机和终端机必须属于224.0.0.1的组
5.所有路由器必须属于224.0.0.2的组
IGMP等协议支持

  • struct hostent

记录主机的信息,包括主机名、别名、地址类型、地址长度和地址列表

struct hostent
{char *h_name; //主机名,即域名char **h_aliases; //主机所有别名构成的字符串数组,同一IP可绑定多个域名int h_addrtype; //主机IP地址的类型,IPv4,IPv6int h_length; //主机IP地址长度,IPv4地址为4,IPv6地址为16char **h_addr_list; //主机ip地址,以网络字节序存储
}
  • gethostbyname()

gethostbyname函数可以利用字符串格式的域名或字符串点分十进制ip,获得IP地址,并且将地址信息装入 hostent 域名结构体

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

返回值
成功返回hostent结构体地址
失败返回NULL指针

  • gethostbyaddr()

使用IP地址获取域名

#include <netdb.h>
struct hostent * gethostbyaddr(const char * addr,socklen_t len,int family);

参数
addr:含有IP地址信息的in_addr结构体指针
len:向第一个参数传递的地址信息的字节数。ipv4为4,ipv6为16
family:传递地址族信息,ipv4为AF_INET,ipv6为AF_INET6

返回值
成功返回hostent结构体地址
失败返回NULL指针

  • struct ip_mreq
struct ip_mreq
{struct in_addr imr_multiaddr; //多播组的IP地址struct in_addr imr_interface; //加入的客户端主机IP地址
}
group_brodcast_recv.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>const int MAX_LINE = 2048;
const int PORT = 8888;
const int BACKLOG = 10;
const int LISTENQ = 6666;
const int MAX_CONNECT = 20;#define BUFLEN 255int main(int argc, char **argv)
{struct sockaddr_in peeraddr;struct in_addr ia;int sockfd;char recmsg[BUFLEN + 1];unsigned int socklen, n;struct hostent *group;struct ip_mreq mreq;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){printf("socket creating err in udptalk\n");exit(EXIT_FAILURE);}bzero(&mreq, sizeof(struct ip_mreq));if (argv[1]){ //传入命令行参数1(主机域名或点分十进制字符串IP)组播地址if ((group = gethostbyname(argv[1])) == (struct hostent *)0)// if((group=gethostbyaddr(argv[1],sizeof(argv[1]),AF_INET))==(struct hostent *)0){perror("gethostbyname");exit(EXIT_FAILURE);}}else{printf("you should give me a group address,224.0.0.0-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地址),写入组播组客户端IP地址列表中if (argv[2]){if (inet_pton(AF_INET, argv[2], &mreq.imr_interface.s_addr) <= 0){printf("Wrong dest IP address!\n");exit(EXIT_FAILURE);}}//设置组播if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1){perror("setsockopt");exit(EXIT_FAILURE);}//绑定组播地址和端口,接收组播信息socklen = sizeof(struct sockaddr_in);bzero(&peeraddr, socklen);peeraddr.sin_family = AF_INET;peeraddr.sin_port = htons(PORT);if (argv[1]){if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0){printf("Wrong dest IP address!\n");exit(EXIT_FAILURE);}}else{printf("you should give me a group address,224.0.0.0-239.255.255.255\n");exit(EXIT_FAILURE);}if (bind(sockfd, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) == -1){printf("Bind error\n");exit(EXIT_FAILURE);}for (;;){bzero(recmsg, BUFLEN + 1);n = recvfrom(sockfd, recmsg, BUFLEN, 0, (struct sockaddr *)&peeraddr, &socklen);if (n < 0){printf("recvfrom err in udptalk\n");exit(EXIT_FAILURE);}else{recmsg[n]=0;printf("perr:%s",recmsg);}}
}
group_brodcast_send.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>const int MAX_LINE = 2048;
const int PORT = 8888;
const int BACKLOG = 10;
const int LISTENQ = 6666;
const int MAX_CONNECT = 20;#define BUFLEN 255int main(int argc, char **argv)
{struct sockaddr_in peeraddr,myaddr;int sockfd;char recmsg[BUFLEN + 1];unsigned int socklen;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){printf("socket creating err in udptalk\n");exit(EXIT_FAILURE);}//组播socklen=sizeof(struct sockaddr_in);bzero(&peeraddr,socklen);peeraddr.sin_family=AF_INET;peeraddr.sin_port=htons(PORT);//组播客户端绑定的端口//命令行参数1为组播地址if (argv[1]){if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0){printf("Wrong dest IP address!\n");exit(EXIT_FAILURE);}}else{printf("you should give me a group address,224.0.0.0-239.255.255.255\n");exit(EXIT_FAILURE);}//绑定本机IP和端口bzero(&myaddr,socklen);myaddr.sin_family=AF_INET;myaddr.sin_port=htons(23456);//命令行参数2为本机IPif (argv[2]){if (inet_pton(AF_INET,argv[2],&myaddr.sin_addr)<=0){printf("self ip address error\n");exit(EXIT_FAILURE);}}elsemyaddr.sin_addr.s_addr=INADDR_ANY;if (bind(sockfd,(struct sockaddr *)&myaddr,sizeof(struct sockaddr_in))==-1){printf("Bind error\n");exit(EXIT_FAILURE);}for(;;){bzero(recmsg,BUFLEN+1);printf("input message to send:");if (fgets(recmsg,BUFLEN,stdin)==(char *)EOF){exit(EXIT_FAILURE);}//发送组播消息if (sendto(sockfd,recmsg,strlen(recmsg),0,(struct sockaddr *)&peeraddr,sizeof(struct sockaddr_in))<0){printf("sendto error\n");exit(EXIT_FAILURE);}printf("send message:%s",recmsg);}
}
  • 接收端

  • 发送端

  • 抓包

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32 HAL库定时器输入捕获SlaveMode脉宽测量

STM32 HAL库定时器输入捕获SlaveMode脉宽测量 SlaveMode模式简介 ✨SlaveMode复位模式&#xff1a;在发生一个触发输入事件时&#xff0c;计数器和它的预分频器能够重新被初始化&#xff1b;同时&#xff0c;如果TIMx_CR1寄存器的URS位为低&#xff0c;还会产生一个更新事件UEV…

Android TextView 在最后一行末尾加图标

当前有个需求.显示一段文本&#xff0c;文本最多显示两行&#xff0c;点击展开后才显示完全。当没有显示完全的时候&#xff0c;需要在文本的第二行末尾显示图标&#xff0c;点击图标和文本&#xff0c;文本展开。难点在于图标需要和第二行文本显示在同一行&#xff0c;高度和文…

windows10 搭建hadoop环境,并且使用hadoop命令

hadoop 环境创建 1. 八、window搭建spark IDEA开发环境 按照步骤安装完 2. windows下安装和配置hadoop 配置环境变量&#xff0c;注意JAVA_HOME路径&#xff0c;修改后&#xff0c;重启电脑&#xff0c;不重启容易报错&#xff01;&#xff01;&#xff01; ​ 新建dat…

【量化课程】02_1.宏观经济学基础概念

2.1_宏观经济学基础概念 文章目录 2.1_宏观经济学基础概念1. 宏观经济简单背景1.1 微观经济学时期1.2 宏观经济学开端1.3 宏观经济学研究的问题1.4 宏观经济与理财的联系 2. 宏观经济分析及关键指标2.1 教材中的宏观经济分析框架和指标2.1.1 国内生产总值GDP2.1.2 边际消费倾向…

Non-Local Video Denoising by CNN

摘要 Non-local patch based methods were until recently state-of-the-art for image denoising but are now outper formed by CNNs. Y et they are still the state-of-the-art for video denoising, as video redundancy is a key factor to attain high denoising perfor…

远程大文件传输工具该怎么选择?

随着网络技术的不断进步&#xff0c;越来越多的人需要在不同地点之间传输文件。这时候&#xff0c;我们便需要使用远程文件传输工具。 1、什么是远程文件传输工具呢&#xff1f; 简单来说&#xff0c;它是一种能够帮助我们在不同设备之间传输文件的工具。通常情况下&#xff0…

【云原生】k8s图形化管理工具之rancher

前言 在前面的k8s基础学习中&#xff0c;我们学习了各种资源的搭配运用&#xff0c;以及命令行&#xff0c;声明式文件创建。这些都是为了k8s管理员体会k8s的框架&#xff0c;内容基础。在真正的生产环境中&#xff0c;大部分的公司还是会选用图形化管理工具来管理k8s集群&…

第八十五天学习记录:C++核心:内存分区模型

内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 1、代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理 2、全局区&#xff1a;存放全局变量和静态变量以及常量 3、栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数…

【探索 Kubernetes|作业管理篇 系列 14】StatefulSet 存储状态

前言 大家好&#xff0c;我是秋意零。 在上一篇中&#xff0c;我们讲解了 StatefulSet 的拓扑状态&#xff1b;我们发现&#xff0c;它的拓扑状态&#xff0c;就是顺序启动/删除、Pod 名称编号命名、将 Pod 名称设为 Hostname 名称、通过 Service 无头服务的 DNS 记录访问。 …

【iOS】—— 编译链接

【iOS】—— 编译链接 文章目录 【iOS】—— 编译链接编译流程预处理&#xff08;预编译Prepressing&#xff09;编译&#xff08;Compilation&#xff09;汇编&#xff08;Assembly&#xff09;链接&#xff08;Linking&#xff09; 编译流程 编译流程分为四步 预处理&#…

使用Vue + FormData + axios实现图片上传功能实战

前言 上节回顾 上一小节中,我们添加了Vue-router的路有数据,这些数据都将是后续实战课程中的真实路由数据了。同时引入了ElementUI的el-menu做为左侧菜单的组件,但本专栏的特点就是遇到第三方功能和组件,自己尽量也要实现一遍,所以,在文章末尾又自己实现了一个tg-menu的…

Vulkan 同步

前言 在前面的文章中&#xff0c;我们讲解了Vulkan的多线程设计理念&#xff0c;分析了其底层的机制。我们知道在Vulkan的设计中&#xff0c;尽量避免资源的同步竞争&#xff0c;但是在某些复杂场景和多线程优化过程中难免会遇到资源竞争的问题&#xff0c;这时候就需要同步机…

Android 生成pdf文件

Android 生成pdf文件 1.使用官方的方式 使用官方的方式也就是PdfDocument类的使用 1.1 基本使用 /**** 将tv内容写入到pdf文件*/RequiresApi(api Build.VERSION_CODES.KITKAT)private void newPdf() {// 创建一个PDF文本对象PdfDocument document new PdfDocument();//创建…

SpringCloud(二)Eureka简介与依赖导入

一、Eureka Eureka能够自动注册并发现微服务&#xff0c;然后对服务的状态、信息进行集中管理&#xff0c;这样当我们需要获取其他服务的信息时&#xff0c;我们只需要向Eureka进行查询就可以了。 像这样的话&#xff0c;服务之间的强关联性就会被进一步削弱。 二、服务注册与…

详解GPT技术发展脉络

文章目录 前言关于本篇的分享内容大语言模型大模型语言模型 百花齐放TransformerAuto-RegressiveResnetLayer-NormMaskScaled Dot-Product AttentionMulti-Head AttenionSelf-AttentionPositional Encoding关于并行计算关于长程依赖Transformer演化 GPT SeriesGPT-1GPT-2GPT-3 …

aidl的学习(1)aidl中java.lang.RuntimeException: Didn‘t create service “XXX“

1、build中版本号为30及以上时&#xff0c;aidl无效&#xff0c;解决方案 ①在客户端的manifest.xml中添加一下代码&#xff0c;其中代码中的包名为服务端的包名 <manifest> ... <application> ....</application> <queries ><package android:na…

如何在 Ubuntu 20.04 桌面上启用/禁用 wayland

Wayland 是一种通信协议&#xff0c;指定显示服务器与其客户端之间的通信。 默认情况下&#xff0c;Ubuntu 20.04 桌面不会启动 Wayland&#xff0c;而是加载 Xorg 显示服务器X11。 在本教程中您将学习&#xff1a; 如何启用 Wayland如何禁用 Wayland 类别要求、约定或使用的…

【自动驾驶汽车量子群粒子过滤器】用于无人驾驶汽车列车定位的量子粒子滤波研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

web前端项目使用electron打包成跨平台桌面端程序(Windows)

文章目录 Electron是什么&#xff1f;快速入门基本使用要求从github下载一个开源项目执行启动脚本运行项目安装electron依赖包编写electron入口文件&#xff0c;在package.json中配置入口文件路径和electron执行脚本启动electron脚本&#xff0c;运行electron应用 应用打包Wind…

1.监控分布式--zabbix

文章目录 监控分布式-zabbix、prometheus概念工作原理功能组件部署zabbix安装Nginx和PHP环境部署数据库编码安装zabbix编译安装zabbix server客户端安装zabbix agent服务 监控分布式-zabbix、prometheus 利用一个优秀的监控软件&#xff0c;我们可以: 通过一个友好的界面进行…