广播UDP的实现

广播UDP的实现

**1.**DUP简介:

协议UDP:全称 User Datagram Protocol,即:用户数据报协议。是面向无连接的协议。

UDP有如下特征:

​ 1.无连接:通信双方不需要实现连接

​ 2.无确认:收到数据不给对方发回执确认

​ 3.不确保有序、丢失不重发

​ 4.采用帧同步的数据报通信方式

​ 简单来讲,UDP类似于寄信,如果两个人除了信件之外没有任何别的通信方式,那么信件寄出去了之后,寄件人是无法得知收件人是否收到信件或者是否已经读取内容的。UDP的特点是无需连接、无需确认、无需缓冲区和分包序列号,因此UDP的效率是比较高的。

UDP适用情况

​ 发送小尺寸数据(如对DNS服务器进行IP地址查询时)在网络环境比较好的情况下,udp的效率比较高。

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

如下图红框选中部分为广播地址 :在这里插入图片描述

2.广播通信过程:

​ 发送方:

​ 1.创建套接字

​ 2.设置为允许进行广播

​ 3.发送数据至广播地址

​ 4.关闭


​ 接收方:

​ 1.创建套接字

​ 2.绑定广播的IP和端口

​ 3.接收数据

​ 4.关闭

3.核心API:

3.1IP地址结构体

struct sockaddr_in addr = {0};
    addr.sin_family =AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY) ;  //服务器IP
    addr.sin_port = htons(PORT);

3.2创建套接字

int socket(int domain, int type,int protocol);

参数

domain- 域,比如因特网AF_INET、UNIX本地域AF_LOCAL等

**type -**套接字类型,比如字节流SOCKET_STREAM、数据报SOCKET_DGRAM等

protocol **-**传输层协议,比如UDP协议IPPROTO_UDP、TCP协议IPPROTO_TCP等返回值
成功返回大于零的套接字文件描述符失败返回-1

3.3绑定地址

int bind(int sockfd,const struct sockaddr *addr, socklen_t addrlen);

参数
**sockfd-**套接字文件描述符
addr - lP地址与端口号,注意需转换成标准地址结构体

​ **addrlen -**地址长度
​ 返回值
​ 成功返回0

​ 失败返回-1

3.4发送UDP数据

 ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

参数
**sockfd -**套接字文件描述符buf-指向要发送的数据的首地址
**len -**要发送的数据的长度(单位:字节)
**flags -**发送标记,比如带外数据MSG_oOB等,一般设置为0

​ **dest_addr -**目标地址,包括lP地址和端口号
​ **addrlen -**目标地址长度
​ 返回值
​ 成功返回已发送的数据(单位:字节)

​ 失败返回-1

3.5接收UDP数据

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)

参数
**sockfd -**套接字文件描述符buf-接收数据缓冲区
**len -**接收数据缓冲区大小(单位:字节)
**flags -**接收标记,比如带外数据MSG_oOB等,一般设置为0
**src_addr -**源端地址,包括IP地址和端口号,不保存源端地址时可设置为NULL

​ **addrlen -**源端地址长度,不保存源端地址时可设置为NULL
​ 返回值
​ 成功返回已接收的数据(单位:字节)

​ 失败返回-1

4.代码以及实现图:

发送方:

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
发送者:
        创建套接字socket();
        设置为允许发送广播权限setsockopt()
        向广播地址发送数据sendto()
*/

int main(int argc, const char *argv[])
{
    if(argc < 3)
    {
        printf("缺少 IP 和端口号\n");
        exit(-1);
    }

    int sockfd;
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("创建套接字失败");
        exit(-1);
    }

    int on = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1)
    {
        perror("设置套接字选项失败");
        exit(1);
    }

    struct sockaddr_in mysockaddr; //创建一个socket地址结构 包含服务器的地址和端口
    mysockaddr.sin_family = AF_INET;  //IPv4地址通信方式
    mysockaddr.sin_port = htons(atoi(argv[2])); //端口号
    mysockaddr.sin_addr.s_addr = inet_addr(argv[1]); // 广播地址
    socklen_t addrlen = sizeof(mysockaddr); //计算并存储结构体,用于sendto函数调用

    char buf[128];
    while (1)
    {
        printf("请输入发送内容:");
        fgets(buf, sizeof(buf), stdin);
        //发送UDP数据
        if(sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&mysockaddr, addrlen) == -1)
        {
            perror("发送数据失败");
            exit(1);
        }
        printf("\n");
    }
    close(sockfd);
    return 0;
}

​ 接收方:

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
    接收者:
            创建套接字socket()
            将套接字与广播的信息结构体绑定bind()
            接收数据recvfrom()
*/

int main(int argc, const char *argv[])
{
    if(argc < 2)
    {
        printf("缺少端口号\n");
        exit(1);
    }

    int sockfd; //创建套接字
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("创建套接字失败");
        exit(1);
    }

    struct sockaddr_in mysockaddr; //创建一个socket地址结构 包含服务器的地址和端口
    mysockaddr.sin_family = AF_INET; //IPv4地址通信方式
    mysockaddr.sin_port = htons(atoi(argv[1])); //端口号
    mysockaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务器ip
    socklen_t addrlen = sizeof(mysockaddr); //计算并存储结构体,用于recvfrom函数调用

    // 绑定地址
    if(bind(sockfd, (struct sockaddr *)&mysockaddr, addrlen) == -1)
    //  套接字文字描述符 ip地址与端口号(强转为地址结构体)  地址长度 //  
    {
        perror("绑定失败");
        exit(1);
    }

    char buf[128];
    struct sockaddr_in sendsockaddr;
    socklen_t sendaddrlen = sizeof(sendsockaddr);//计算并存储结构体 用于recvfrom函数调用

    while (1)
    {
        //接收UDP数据
        if(recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&sendsockaddr, &sendaddrlen) == -1)
        {
            perror("接收数据失败");
            exit(1);
        }
        printf("[%s - %d]: %s\n", inet_ntoa(sendsockaddr.sin_addr), ntohs(sendsockaddr.sin_port), buf);
    }

    close(sockfd);

    return 0;
}

实现图:

发送方发送数据给接收方显示:在这里插入图片描述

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值