UDP-组播,广播

news2024/11/26 5:45:30

转自: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);
    }else
        printf("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);
    }else
        printf("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/24
    else{
        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.255
  create 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,IPv6
    int h_length; //主机IP地址长度,IPv4地址为4,IPv6地址为16
    char **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 255

int 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 255

int 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为本机IP
    if (argv[2])
    {
        if (inet_pton(AF_INET,argv[2],&myaddr.sin_addr)<=0)
        {
            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))==-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.coloradmin.cn/o/773929.html

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

相关文章

python 100以内的质数

可以使用for循环 # 求100以内的质数 i 2 for j in range(1, 101): #如果100以内的数字除以2的余数等于0if (j % i 0): #如果是就跳过&#xff0c;继续下一个循环continueprint(j) 要找出从1到100之间的质数&#xff0c;你可以使用嵌套循环和判断条件来实现。 print("…

硬中断、软中断详解

文章目录 什么是中断&#xff1f; 什么是计算机的中断&#xff1f; 什么叫硬中断、什么叫软中断&#xff1f; 怎么查看硬中断、软中断 查看硬中断的运行情况 cat /proc/interrupts 查看软中断的运行情况 cat /proc/softirqs 怎么排查软中断过高的问题&#xff1f; 软中断注意事…

win11 win+e 打开我的电脑

在打开的【文件资源管理器】中&#xff0c;找到【选项】菜单&#xff0c;并点击该菜单 在打开的弹框中&#xff0c;将选项卡切换到【常规】&#xff0c;将【打开文件资源管理器时打开】后的下拉框&#xff0c;选择为【此电脑】&#xff0c;然后&#xff0c;点击保存即可。到此&…

8.1Java EE——Spring AOP

Spring的AOP模块是Spring框架体系中十分重要的内容&#xff0c;该模块一般适用于具有横切逻辑的场景&#xff0c;如访问控制、事务管理和性能监控等 一、AOP概述 AOP的全称是Aspect Oriented Programming&#xff0c;即面向切面编程。和OOP不同&#xff0c;AOP主张将程序中相同…

AndroidStudio中添加翻译插件:Translation

背景 开发中经常要阅读源码等&#xff0c;就会涉及翻译&#xff08;特别是英语不好的在下&#xff09;&#xff0c;之前一直是复制到百度或者谷歌进行翻译。终于&#xff0c;偶然找到了一款好用的as内直接用的翻译插件。 安装流程 1. 安装插件 打开as&#xff0c;依次点击&am…

【动手学深度学习】--11.经典卷积神经网络 LeNet

文章目录 经典卷积神经网络 LeNet1.LeNet2.代码实现3.模型训练 经典卷积神经网络 LeNet 学习视频&#xff1a;经典卷积神经网络 LeNet【动手学深度学习v2】 官方笔记&#xff1a;卷积神经网络&#xff08;LeNet&#xff09; 1.LeNet 总体来看&#xff0c;LeNet&#xff08;L…

SpringBoot如何启用/禁用执行器?

SpringBoot如何启用/禁用执行器&#xff1f; 一、什么是SpringBoot执行器二、如何启用SpringBoot执行器三、如何禁用SpringBoot执行器 一、什么是SpringBoot执行器 在Spring Boot中&#xff0c;执行器&#xff08;Actuator&#xff09;是一个用于监控和管理应用程序的功能模块…

关于WIN10创建系统映像时D盘为系统盘的解决方案

文章目录 问题&#xff1a;使用WIN10自带备份工具时&#xff0c;创建系统映像时&#xff0c;D盘被识别为系统盘的解决方案。方法一&#xff08;传统方法&#xff0c;删盘符&#xff09;方法二&#xff08;对症下药&#xff0c;找原因&#xff09;第一个选项是暂时将服务的Image…

Nature Neuroscience:慢波、纺锤波和涟波耦合如何协调人类睡眠期间的神经元加工和通信

摘要 学习和可塑性依赖于休息期间神经元回路的微调调节。一个尚未解决的难题是&#xff0c;在没有外部刺激或有意识努力的情况下&#xff0c;睡眠中的大脑如何协调神经元的放电率(FRs)以及神经回路内外的通信&#xff0c;以支持突触和系统巩固。利用颅内脑电图对人类海马体和周…

SuperGlue学习记录之最优传输

在进行最优传输相关理论的学习过程中&#xff0c;找到SuperGlue这篇论文&#xff0c;该篇论文通过最优传输来完成特征点的匹配过程。 SuperGlue结构 先来看一下其结构&#xff1a; 首先将两张图片送入特征提取网络&#xff0c;通过卷积网络提取出特征&#xff0c;主要有四个值…

Windows特殊名称文件夹删除

问题描述&#xff1a; 使用React开发的前端项目&#xff0c;指定build输出路径是创建出了俩个特殊的文件夹 .. build 咋一看build显得很正常&#xff0c;那你是没看见同时出现了俩个build&#xff1a; 尝试使用 dir /x rd /S /Q 等删除目录无果 尝试下载删除文件夹的工具也没…

【windows测试通过】关于Godot导入外部音频文件的问题

file.open(filepath, file.READ) var buffer file.get_buffer(file.get_len()) #put data into audiostreamsample var stream AudioStreamSample.new() stream.data buffer 代码给出&#xff0c;还没有测试过。(godot3.2测试未通过&#xff09; 在运行时轻松加载外部音频…

大数据传输安全风险与预防措施

随着互联网技术的快速发展和大数据时代的到来&#xff0c;大数据传输已成为越来越重要的环节。但由于网络传输过程中存在着各种安全风险&#xff0c;这些风险极有可能会导致机密数据泄露、网络攻击等问题&#xff0c;对企业和个人的信息安全造成潜在的威胁。因此&#xff0c;保…

【个人笔记】对linux中一切皆文件的理解与ls命令

目录 Linux中一切皆文件ls命令常用参数常用命令lscpu lspci Linux中一切皆文件 理解参考&#xff1a;为什么说&#xff1a;Linux中一切皆文件&#xff1f; ls命令 ls&#xff08;英文全拼&#xff1a; list directory contents&#xff09;命令用于显示指定工作目录下之内容…

数据可视化组件有什么用?

数据可视化组件在数据分析中扮演着至关重要&角色。 通过图表、图形和交互式界面&#xff0c;数据可视化组件帮助将复杂的数据转化为易于理解的视觉展示。这种形式的数据呈现有助于发现模式、趋势和异常&#xff0c;并能够快速有效地传达数据的含义和洞察。 下面简单举两个…

volatile 关键字 (详细解析)

目录 前置知识 共享变量不可见性 JMM volatile 关键字 使用volatile关键字 加锁 volatile 关键字 -- 更深入的问题 volatile不保证原子性 volatile禁止指令重排序 前置知识 共享变量不可见性 在多线程并发执行下&#xff0c;多个线程修改共享的成员变量&#xff0…

Android自动化测试之uiautomator2使用

uiautomator2是uiautomator的升级版本&#xff0c;增加了对AccessibilityService服务的支持&#xff0c;当然在appium1.7版本以上进行支持&#xff0c;本篇文章介绍一下它的使用。 安装 安装方式很简单&#xff1a; pip install uiautomator2 进行初始化&#xff1a; pyth…

java版Spring Cloud+Spring Boot+Mybatis+uniapp 企业电子招投标采购系统源码

随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及审计监督要…

zabbix 企业级监控(2) 监控linux主机

目录 配置开始 Zabbix添加linux主机 4.为agent.zabbix.com添加模板 环境&#xff1a; &#xff08;隔天做的更换了IP&#xff0c;不影响实际操作&#xff09; IP 192.168.50.50 关闭防火墙规则 更改主机名 [rootlocalhost ~]# vim /etc/hostname agent.zabbix.com [rootloca…

myAgv智能移动底盘的slam算法学习以及动态避障

前言 随着科技得越来越发达&#xff0c;人工智能&#xff0c;自动驾驶导航等字眼频频出现在我们得眼前。但是目前来说自动驾驶并没有得到很全面得普及&#xff0c;还在进行不断的开发和测试当中。从小就爱好车的我&#xff0c;对这项技术也很是感兴趣。 偶然间在上网的时候买…