linux udp广播数据包实际用例

1.说明

本节说明的是在实际案例中使用udp广播数据包产生的问题以及记录。

2.广播数据包服务端与客户端代码用例

2.1 服务端客户端广播数据包发送与接收

第一种场景,服务端部署在A机器,客户端部署在B机器。 服务端代码server.c,如下:

c 复制代码
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <ifaddrs.h>
#include <net/if.h>

#define UDP_NOTIFY_PORT  20000

int udp_socket_server_init(struct sockaddr_in *saddr)
{
	int optval = 1, fd = -1;
	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("cannot setup socket \n");
		return -1;
	}
	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0)
	{
		printf("cannot set socket setting \n");
		close(fd);
		return -1;
	}

    // struct ifreq ifr;
    // memset(&ifr, 0, sizeof(ifr));
	// snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lo");
	// if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {		
	// 	printf("setsockopt fail\n");
	// }

	saddr->sin_family= AF_INET;
	saddr->sin_port=htons(UDP_NOTIFY_PORT);
	saddr->sin_addr.s_addr= htonl(INADDR_BROADCAST);
    if(-1 == bind(fd,(struct sockaddr *)saddr,sizeof(struct sockaddr)))
    {
        printf("Failed to bind socket server\n");
        close(fd);
        return -1;
    }
	return fd;
}

// unsigned char matchLocalIp(char *pSrcIp, int ipLen)
// {
//     struct ifaddrs *ifaddr, *ifa;
//     char ip[INET_ADDRSTRLEN];

//     if(ip == NULL)
//         return 0;

//     unsigned char findIp = 0;

//     if (getifaddrs(&ifaddr) == -1) {
//         return findIp;
//     }
//     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
//         if (ifa->ifa_addr == NULL)
//             continue;
//         const int family = ifa->ifa_addr->sa_family;
//         if (family != AF_INET && family != AF_INET6) {
//             continue;
//         }  
//         const char *ifa_name = ifa->ifa_name;
//         printf("ifa name: %s\n", ifa_name);                       

//         struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr;
//         inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN);
//         printf("interface: %s, IP: %s\n", ifa->ifa_name, ip);

//         if((ipLen == strlen(ip)) && (strncmp(ip, pSrcIp, ipLen) == 0))
//         {
//             findIp = 1;
//         }
//     }

//     freeifaddrs(ifaddr);

//     return findIp;
// }


int main()
{
    struct sockaddr_in udp_addr = {0}, addr_len = {0};
    int udp_fd = udp_socket_server_init(&udp_addr);
    if (udp_fd < 0) {
        printf("failed to init server\n");
        return -1;
    }
    
    int buffer = 0;
    socklen_t len = sizeof(addr_len);
    int n = 0;

    while (1) {

        memset(&buffer, 0, sizeof(buffer));
        n = 0;
        while (n <= 0 ) {
            printf("Start recvfrom form broadcast.\n");
            n = recvfrom(udp_fd, &buffer, sizeof(buffer), MSG_WAITALL,
                         (struct sockaddr *)&udp_addr, &len);
            if (n <= 0) {
                printf("Error while receiving broadcast\n");
                continue;
            }

            printf("client IPAddr = %s, Port = %d\n", inet_ntoa(udp_addr.sin_addr), ntohs(udp_addr.sin_port));
            
            switch (buffer)
            {
                case 0 :    // host reset event
                {
                    //printf("client IPAddr = %s\n", (char * )inet_ntoa(udp_addr.sin_addr));
                    n = -1; // continue with n <= 0 
                    
                    printf(" buffer = %d\n", buffer);
                    // char *ip = inet_ntoa(udp_addr.sin_addr);
                    // if(ip == NULL)
                    // {
                    //     continue;
                    // }
                    // if(matchLocalIp(ip,strlen(ip)) == 0)
                    // {
                    //     printf("from other device ,should ignore.\n");
                    // }
                    // else
                    // {
                    //     printf("from self device ,should not ignore.\n");
                    // }
                }
                break;
                case 1 :
                {
                    printf("[line:%d] Received broadcast, buffer = %d\n", __LINE__,buffer);
                }
                break;
                default :
                {
                    printf("[line:%d] Received broadcast, buffer = %d\n", __LINE__,buffer);
                }   
                break;
            }             
        }
    }    
    
    return 0;
}

客户端代码client.c,如下:

c 复制代码
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>


#define UDP_NOTIFY_PORT  20000

int Socket;
struct sockaddr_in SockAddr;

int udp_socket_client_init()
{
    int optval = 1;
    struct ifreq ifr;
	if((Socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("cannot setup socket \n");
		return -1;
	}
	if(fcntl(Socket,F_SETFL,O_NONBLOCK) < 0)
	{
		printf("cannot set IO mechanism \n");
		close(Socket);
		return -1;
	}
	if(setsockopt(Socket,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int)) < 0)
	{
		printf("cannot set socket setting \n");
		close(Socket);
		return -1;
	}
	// memset(&ifr, 0, sizeof(ifr));
	// snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lo");
	// if (setsockopt(Socket, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {		
	// 	printf("setsockopt fail\n");
	// }	

	SockAddr.sin_family= AF_INET;
	SockAddr.sin_port=htons(UDP_NOTIFY_PORT);
	SockAddr.sin_addr.s_addr= inet_addr("255.255.255.255");
}


void UDPNotify(int initialized)
{
	int retval = 0;
	int event[1] = {initialized};
	socklen_t len = sizeof(struct sockaddr);
	int ret = 0;

	retval = sendto(Socket, event, 1, 0, (struct sockaddr *)&SockAddr, len);
	if(retval < 0)
	{
		printf("Fail to broadcast\n");
	}
}

int main()
{
    udp_socket_client_init();

    UDPNotify(1);
    return 0;
}

分别在A机器与B机器编译执行:

c 复制代码
# gcc server.c -o server  //A机器
# ./server                //A机器
# gcc client.c -o client  //B机器
# ./client

A机器服务端打印结果如下:

或者在B机器执行如下命令:

c 复制代码
# echo "1" | socat - UDP4-DATAGRAM:255.255.255.255:20000,broadcast

打印数据如下:

可以在A机器部署2个服务端,可以看到如下打印:

2.2 客户端本机广播数据包

客户端可以绑定本机,只在本机广播数据包,而不是广播到整个局域网。

客户端代码client.c如下,绑定lo网络设备:

c 复制代码
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>


#define UDP_NOTIFY_PORT  20000

int Socket;
struct sockaddr_in SockAddr;

int udp_socket_client_init()
{
    int optval = 1;
    struct ifreq ifr;
	if((Socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("cannot setup socket \n");
		return -1;
	}
	if(fcntl(Socket,F_SETFL,O_NONBLOCK) < 0)
	{
		printf("cannot set IO mechanism \n");
		close(Socket);
		return -1;
	}
	if(setsockopt(Socket,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int)) < 0)
	{
		printf("cannot set socket setting \n");
		close(Socket);
		return -1;
	}
	memset(&ifr, 0, sizeof(ifr));
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lo");
	if (setsockopt(Socket, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {		
		printf("setsockopt fail\n");
	}	

	SockAddr.sin_family= AF_INET;
	SockAddr.sin_port=htons(UDP_NOTIFY_PORT);
	SockAddr.sin_addr.s_addr= inet_addr("255.255.255.255");
}


void UDPNotify(int initialized)
{
	int retval = 0;
	int event[1] = {initialized};
	socklen_t len = sizeof(struct sockaddr);
	int ret = 0;

	retval = sendto(Socket, event, 1, 0, (struct sockaddr *)&SockAddr, len);
	if(retval < 0)
	{
		printf("Fail to broadcast\n");
	}
}

int main()
{
    udp_socket_client_init();

    UDPNotify(1);
    return 0;
}

这个时候仍将客户端部署在B机器上,执行之后,可以看到A机器(服务端)不会收到客户端数据包

那么将客户端部署到A机器上,(客户端与服务端在一台机器上),这个时候可以看到服务端能收到客户端的数据包。

2.3 服务端本机广播数据包

修改服务端server.c代码如下,绑定lo网络设备:

c 复制代码
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <ifaddrs.h>
#include <net/if.h>

#define UDP_NOTIFY_PORT  20000

int udp_socket_server_init(struct sockaddr_in *saddr)
{
	int optval = 1, fd = -1;
	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("cannot setup socket \n");
		return -1;
	}
	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0)
	{
		printf("cannot set socket setting \n");
		close(fd);
		return -1;
	}

    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lo");
	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {		
		printf("setsockopt fail\n");
	}

	saddr->sin_family= AF_INET;
	saddr->sin_port=htons(UDP_NOTIFY_PORT);
	saddr->sin_addr.s_addr= htonl(INADDR_BROADCAST);
    if(-1 == bind(fd,(struct sockaddr *)saddr,sizeof(struct sockaddr)))
    {
        printf("Failed to bind socket server\n");
        close(fd);
        return -1;
    }
	return fd;
}

// unsigned char matchLocalIp(char *pSrcIp, int ipLen)
// {
//     struct ifaddrs *ifaddr, *ifa;
//     char ip[INET_ADDRSTRLEN];

//     if(ip == NULL)
//         return 0;

//     unsigned char findIp = 0;

//     if (getifaddrs(&ifaddr) == -1) {
//         return findIp;
//     }
//     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
//         if (ifa->ifa_addr == NULL)
//             continue;
//         const int family = ifa->ifa_addr->sa_family;
//         if (family != AF_INET && family != AF_INET6) {
//             continue;
//         }  
//         const char *ifa_name = ifa->ifa_name;
//         printf("ifa name: %s\n", ifa_name);                       

//         struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr;
//         inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN);
//         printf("interface: %s, IP: %s\n", ifa->ifa_name, ip);

//         if((ipLen == strlen(ip)) && (strncmp(ip, pSrcIp, ipLen) == 0))
//         {
//             findIp = 1;
//         }
//     }

//     freeifaddrs(ifaddr);

//     return findIp;
// }


int main()
{
    struct sockaddr_in udp_addr = {0}, addr_len = {0};
    int udp_fd = udp_socket_server_init(&udp_addr);
    if (udp_fd < 0) {
        printf("failed to init server\n");
        return -1;
    }
    
    int buffer = 0;
    socklen_t len = sizeof(addr_len);
    int n = 0;

    while (1) {

        memset(&buffer, 0, sizeof(buffer));
        n = 0;
        while (n <= 0 ) {
            printf("Start recvfrom form broadcast.\n");
            n = recvfrom(udp_fd, &buffer, sizeof(buffer), MSG_WAITALL,
                         (struct sockaddr *)&udp_addr, &len);
            if (n <= 0) {
                printf("Error while receiving broadcast\n");
                continue;
            }

            printf("client IPAddr = %s, Port = %d\n", inet_ntoa(udp_addr.sin_addr), ntohs(udp_addr.sin_port));
            
            switch (buffer)
            {
                case 0 :    // host reset event
                {
                    //printf("client IPAddr = %s\n", (char * )inet_ntoa(udp_addr.sin_addr));
                    n = -1; // continue with n <= 0 
                    
                    printf(" buffer = %d\n", buffer);
                    // char *ip = inet_ntoa(udp_addr.sin_addr);
                    // if(ip == NULL)
                    // {
                    //     continue;
                    // }
                    // if(matchLocalIp(ip,strlen(ip)) == 0)
                    // {
                    //     printf("from other device ,should ignore.\n");
                    // }
                    // else
                    // {
                    //     printf("from self device ,should not ignore.\n");
                    // }
                }
                break;
                case 1 :
                {
                    printf("[line:%d] Received broadcast, buffer = %d\n", __LINE__,buffer);
                }
                break;
                default :
                {
                    printf("[line:%d] Received broadcast, buffer = %d\n", __LINE__,buffer);
                }   
                break;
            }             
        }
    }    
    
    return 0;
}

客户端仍然部署在B机器上,但是可以广播到局域网,client.c代码如下:

c 复制代码
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>


#define UDP_NOTIFY_PORT  20000

int Socket;
struct sockaddr_in SockAddr;

int udp_socket_client_init()
{
    int optval = 1;
    struct ifreq ifr;
	if((Socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("cannot setup socket \n");
		return -1;
	}
	if(fcntl(Socket,F_SETFL,O_NONBLOCK) < 0)
	{
		printf("cannot set IO mechanism \n");
		close(Socket);
		return -1;
	}
	if(setsockopt(Socket,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int)) < 0)
	{
		printf("cannot set socket setting \n");
		close(Socket);
		return -1;
	}
	// memset(&ifr, 0, sizeof(ifr));
	// snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lo");
	// if (setsockopt(Socket, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {		
	// 	printf("setsockopt fail\n");
	// }	

	SockAddr.sin_family= AF_INET;
	SockAddr.sin_port=htons(UDP_NOTIFY_PORT);
	SockAddr.sin_addr.s_addr= inet_addr("255.255.255.255");
}


void UDPNotify(int initialized)
{
	int retval = 0;
	int event[1] = {initialized};
	socklen_t len = sizeof(struct sockaddr);
	int ret = 0;

	retval = sendto(Socket, event, 1, 0, (struct sockaddr *)&SockAddr, len);
	if(retval < 0)
	{
		printf("Fail to broadcast\n");
	}
}

int main()
{
    udp_socket_client_init();

    UDPNotify(1);
    return 0;
}

可以看到A服务端是收不到B客户端的数据的。

将客户端部署在A机器上,然后绑定lo设备:

c 复制代码
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>


#define UDP_NOTIFY_PORT  20000

int Socket;
struct sockaddr_in SockAddr;

int udp_socket_client_init()
{
    int optval = 1;
    struct ifreq ifr;
	if((Socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("cannot setup socket \n");
		return -1;
	}
	if(fcntl(Socket,F_SETFL,O_NONBLOCK) < 0)
	{
		printf("cannot set IO mechanism \n");
		close(Socket);
		return -1;
	}
	if(setsockopt(Socket,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int)) < 0)
	{
		printf("cannot set socket setting \n");
		close(Socket);
		return -1;
	}
	memset(&ifr, 0, sizeof(ifr));
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lo");
	if (setsockopt(Socket, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {		
		printf("setsockopt fail\n");
	}	

	SockAddr.sin_family= AF_INET;
	SockAddr.sin_port=htons(UDP_NOTIFY_PORT);
	SockAddr.sin_addr.s_addr= inet_addr("255.255.255.255");
}


void UDPNotify(int initialized)
{
	int retval = 0;
	int event[1] = {initialized};
	socklen_t len = sizeof(struct sockaddr);
	int ret = 0;

	retval = sendto(Socket, event, 1, 0, (struct sockaddr *)&SockAddr, len);
	if(retval < 0)
	{
		printf("Fail to broadcast\n");
	}
}

int main()
{
    udp_socket_client_init();

    UDPNotify(1);
    return 0;
}

A服务端能收到数据。

因此,服务端与客户端均绑定lo设备,广播数据包将不会扩散到局域网以及服务端不会收到来自局域网的数据包。

相关推荐
s090713617 小时前
ZYNQ DMA to UDP 数据传输系统设计文档
网络协议·fpga开发·udp
偶像你挑的噻17 小时前
9-Linux驱动开发-设备树=>设备树插件实现 RGB 灯驱动
linux·驱动开发·stm32·嵌入式硬件
叫致寒吧17 小时前
Nginx基于域名的虚拟主机实操案例
运维·服务器·nginx
梁正雄18 小时前
linux服务-Nginx+Tomcat+Redis之Session 共享 - 容器compose
linux·nginx·tomcat
咕噜签名-铁蛋18 小时前
云服务器与物理服务器、VPS的区别
运维·服务器
恒创科技HK18 小时前
香港服务器流量有限制和带宽有限制区别在哪?
运维·服务器·网络
fengyehongWorld18 小时前
Linux rsync命令
linux
wanhengidc18 小时前
机架式服务器有什么作用?
运维·服务器·web安全·智能手机·云计算
干啥都是小小白19 小时前
Linux C编程
linux·运维·服务器
hazy1k19 小时前
ESP32基础-Socket通信 (TCP/UDP)
c语言·单片机·嵌入式硬件·网络协议·tcp/ip·udp·esp32