使用UDP实现广播-使用 setsockopt 设置发送端允许发送广播权限-传输层

使用UDP实现广播

在这里插入图片描述

概念

只有用户数据报(UDP协议)套接字才能广播

同时发给局域网中的所有主机,称为广播

具体广播地址 可以通过 ifconfig 命令 看 关键字 broadcast 后面的地址
在这里插入图片描述

广播的用处

ARP协议 通过 IP 地址获取对方的mac地址,就是使用广播实现的。

广播的流程

-------
发送者:|
-------	1.创建套接字 socket( )
        -----------------------------------
		2.设置为允许发送广播权限 setsockopt( )
        -----------------------------------
		3.填充广播信息结构体 sockaddr_in
		4.发送数据 sendto( )
接收者:
		1.创建套接字 socket( )
		2.填充广播信息结构体 sockaddr_in
		3.将套接字与广播信息结构体绑定 bind( )
		4.接收数据 recvfrom( )

使用 setsockopt 设置允许发送广播权限

#include <sys/types.h>          
#include <sys/socket.h>

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

参数:
	sockfd:套接字
	
	level:选项的级别
		   SOL_SOCKET	套接字级别
		
	optname:选项的名称
			 SO_BROADCAST	是否允许发送广播
  
  	optval:结构体
			1 允许
			0 不允许

	optlen:optval的大小

setsockopt 其他用法

代码实现

接收端—01receive.c

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

#define ERRLOG(errmsg)                                       \
	do                                                       \
	{                                                        \
		printf("%s--%s(%d):", __FILE__, __func__, __LINE__); \
		perror(errmsg);                                      \
		exit(-1);                                            \
	} while (0)

//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind(const char *argv[]);

int main(int argc, const char *argv[])
{
	//检测命令行参数个数
	if (3 != argc)
	{
		printf("Usage : %s <IP> <PORT>\n", argv[0]);
		exit(-1);
	}

	//创建套接字-填充服务器网络信息结构体-绑定
	int sockfd = socket_bind(argv);

	//用来保存发送端信息的结构体
	// UPD网络通信 如果需要给发送端回信,就必须保存发送端的网络信息结构体
	struct sockaddr_in client_addr;
	memset(&client_addr, 0, sizeof(client_addr));
	socklen_t client_addr_len = sizeof(client_addr);

	char buff[128] = {0};

	while (1)
	{
		//阻塞接收发送端发来的数据
		if (-1 == recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&client_addr, &client_addr_len))
			ERRLOG("recvfrom error");

		printf("客户端 (%s:%d) 发来数据:[%s]\n",
			   inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buff);
	}
	//关闭监听套接字  一般不关闭
	close(sockfd);

	return 0;
}

//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind(const char *argv[])
{
	// 1.创建套接字      //IPV4   //UDP
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd)
		ERRLOG("socket error");

	// 2.填充广播信息结构体
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	//端口号  填 8888 9999 6789 ...都可以
	server_addr.sin_port = htons(atoi(argv[2]));
	// ip地址 组播的IP地址  224.0.0.1 – 239.255.255.255
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);

	//结构体长度
	socklen_t server_addr_len = sizeof(server_addr);

	// 3.将套接字和组播信息结构体绑定
	if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, server_addr_len))
		ERRLOG("bind error");

	return sockfd;
}

发送端—02send.c

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

#define ERRLOG(errmsg)                                       \
    do                                                       \
    {                                                        \
        printf("%s--%s(%d):", __FILE__, __func__, __LINE__); \
        perror(errmsg);                                      \
        exit(-1);                                            \
    } while (0)

int main(int argc, const char *argv[])
{
    //检测命令行参数个数
    if (3 != argc)
    {
        printf("Usage : %s <IP> <PORT>\n", argv[0]);
        exit(-1);
    }

    // 1.创建套接字      //IPV4   //UDP
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
        ERRLOG("socket error");

    // 2.填充组播信息结构体
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr)); // 清空
    server_addr.sin_family = AF_INET;             // IPV4
    //端口号  填 8888 9999 6789 ...都可以
    // atoi字符串转换成整型数
    // htons将无符号2字节整型  主机-->网络
    server_addr.sin_port = htons(atoi(argv[2]));

    // ip地址 是广播的ip地址 192.168.xxx.255
    // inet_addr字符串转换成32位的网络字节序二进制值
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);

    //结构体长度
    socklen_t server_addr_len = sizeof(server_addr);
    
/*---------------------------------------------------------------------------------*/
    //设置允许发送广播
	int on_off = 1;		//允许
	//                  /套接字  /套接字级别 /是否允许发送广播
	if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on_off, sizeof(on_off)))
		ERRLOG("setsockopt error");
/*---------------------------------------------------------------------------------*/

    char buff[128] = {0};

    while (1)
    {
        printf("请输入 : ");
        scanf("%s", buff);
        if (0 == strcmp(buff, "quit"))
            break;

        //将数据以广播的形式发送----发送到广播的ip地址
        if (-1 == sendto(sockfd, buff,sizeof(buff), 0, (struct sockaddr *)&server_addr, server_addr_len))
            ERRLOG("sendto error");
        
    }
    //关闭监听套接字  一般不关闭
    close(sockfd);

    return 0;
}

执行结果

在这里插入图片描述

注意

发送端 使用 setsockopt 设置允许发送广播权限

应该插放socket创建套接字 之后,sendto将数据以广播的形式发送之前

设置允许发送广播
	int on_off = 1;		//允许
	                    /套接字  /套接字级别 /是否允许发送广播
	if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on_off, sizeof(on_off)))
		ERRLOG("setsockopt error");

6.非原创

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值