Linux下UDP接收广播的方法 (linux udp 接收广播)

在网络通信中,广播是一种重要的传输方式。广播可以将一条信息同时发送给所有主机,可用于向多个主机传输同一类型的信息,例如网络状态信息、文件共享请求等。而UDP是无连接的数据报协议,其传输效率高,并且由于不需要建立连接,所以在广播中也被广泛使用。本文将介绍在Linux操作系统下使用UDP接收广播的方法。

一、UDP广播的概念

UDP广播是指发送端将UDP数据报发送到某一IP地址的所有主机,它是半双工模式的通信方式,即发送方发送信息后,不等待接收方的应答即可继续发送下一个信息。UDP广播是一种不可靠的传输方式,由于UDP本身没有错误检查、确认重传、流量控制等机制,所以广播消息在传输过程中有丢失、重复、乱序等问题。

二、UDP广播的应用场景

UDP广播可用于以下场景:

1、网络状态信息:网络管理员可以通过向网段内所有主机发送广播包,获取主机的IP地址、MAC地址等网络状态信息;

2、文件共享请求:一台主机可以通过向局域网内的所有主机发送广播试图查找其他主机共享的文件;

3、在线游戏:在线游戏中需要向所有玩家发送游戏信息,例如位置变化、消息通知等;

4、多播应用:多播应用可以利用广播技术向一组主机发送相同的信息。

三、Linux下UDP广播的接收方法

在Linux操作系统下,我们可以使用socket API来创建UDP套接字,并通过设置socket选项来实现UDP广播的接收。

1、创建UDP套接字

使用socket函数创建UDP套接字:

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

该函数返回一个整型的套接字描述符,domn指定套接字的通信域,使用AF_INET表示IPv4协议;type指定套接字的类型,使用SOCK_DGRAM表示UDP数据报套接字;protocol指定协议类型,通常为0表示使用默认协议。

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

2、设置socket选项

必须设置SO_REUSEADDR选项,否则后续的bind操作可能会报错,因为套接字地址已被占用。同时,还需要设置SO_BROADCAST选项,以允许广播传输。

struct timeval timeout={5,0};//5s

setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

int optval = 1;

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));

SO_RCVTIMEO选项可以设置接收超时时间,单位为秒和微秒,当设定时间未收到数据,接收函数会返回-1,并渲染errno为EWOULDBLOCK。

3、绑定UDP端口

使用bind函数将UDP套接字绑定到一个端口上:

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

该函数将套接字描述符sockfd绑定到地址addr,并指定地址长度addrlen。在UDP广播中,可以将端口设置为0,表示让内核自动分配端口号。

struct sockaddr_in serveraddr;

bzero(&serveraddr, sizeof(serveraddr));

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

serveraddr.sin_port = htons(UDP_PORT);

bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

4、接收广播数据

使用recvfrom函数从UDP套接字中接收数据:

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

该函数将从UDP套接字sockfd中接收更大长度为len的数据,存储到buf中,并将数据源地址保存在src_addr中。flags为接收标志,此处可设为0表示阻塞接收。addrlen是地址长度的指针,存储接收到的地址的长度。该函数返回实际接收的大小,如果发生错误,返回-1。

char recvbuf[UDP_MAX_LEN];

struct sockaddr_in clientaddr;

socklen_t clientaddrlen = sizeof(clientaddr);

ssize_t n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&clientaddr, &clientaddrlen);

五、示例程序

#include

#include

#include

#include

#include

#include

#include

#define UDP_PORT (12345) // 广播端口

#define UDP_MAX_LEN (1024) // UDP数据报更大长度

int mn(int argc, char **argv)

{

// 创建UDP套接字

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

if(sockfd

{

printf(“create socket fled!\n”);

return -1;

}

// 设置socket选项

struct timeval timeout={5,0};//5s

setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

int optval = 1;

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));

// 绑定UDP端口

struct sockaddr_in serveraddr;

bzero(&serveraddr, sizeof(serveraddr));

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

serveraddr.sin_port = htons(UDP_PORT);

bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

// 接收广播数据

char recvbuf[UDP_MAX_LEN];

struct sockaddr_in clientaddr;

socklen_t clientaddrlen = sizeof(clientaddr);

while(1)

{

ssize_t n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&clientaddr, &clientaddrlen);

if(n > 0)

{

recvbuf[n] = ‘\0’;

printf(“recv from %s:%d, data: %s\n”, inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), recvbuf);

// TODO: 对接收到的广播数据进行处理

}

}

// 关闭UDP套接字

close(sockfd);

return 0;

}

六、

相关问题拓展阅读:

linux下udp连接问题。

要用基于端口的NAT,NPAT,UDP才能穿越

如果说你想让vmware中的linux互相访问,你这么做虚拟机的网卡应该是不可以的,你必须将两个虚拟机的网卡模式都做成一样的,要么NAT,要么桥接,NAT的话要看你NAT的是哪个虚拟网卡,说起来比较麻烦,还滑吵宴是建议用桥碰态接模式,至于你说的UDP,没有什么穿透的概信银念,你只要将两个虚拟机能互相ping通,UDP就可以互相访问。

linux中inaddr_broadcast什么意思

1、广播地址

broadcast广播的意思嘛

2、在

IP地址

中,如果最后一个数字是255,则一定是一咐闹戚个广播地址。

#网络广播

子网划分

的网络内广播,由于当强的网络均涉及子网划分,故此种地址很少存在;

#受限广播均不转发衡陵此类广播

#子网广播行广播,比如192.168是网络ID,那么192.168.1.255就是子网192.168.1的广播

#全部子网广播.168.255.255

3、广播要采用UDP的方式,具体弯册流程如下:

创建UDP套接字

设置套接字属性为SO_BROADCAST,设置为广播地址

设置广播地址为INADDR_BROADCAST,同时也要指定发送端口

进行数据收发操作

使用recvfrom接收UDP包在Windows和Linux平台的不同表现

操作系统的UDP接收流程如下:收到一个州芹派UDP包后,验证没有错误后,放入一个包队列中,队列中的每一个元素就是一个完整的UDP包。当应用程序通过recvfrom()读取时,OS把相应的一个完整UDP包取出,然后拷贝到用户提供的内存中,物理用户提供的内存大小册贺是多少,OS都会完整取出一个UDP包。如果用户提供的内存小于这个UDP包的大小,那么在填充慢内存后,UDP包剩余的部分就会被丢弃,以后再也无法取回。

这与TCP接收完全不同,TCP没有完整包的概念,也没有边界,OS只会取出用户要求的大小,剩余的仍然保留在OS中,下次还可以继续取出。

socket编程虽然是事实上的标准,而且不同平台提供的接口函数也非常类似,但毕竟它不存在严格的标首答准。所以各个平台的实现也不完全兼容。下面就从recvfrom()这个函数看看Window平台和Linux平台的不同。

Windows平台的表现

int

WSAAPI

recvfrom(

_In_ SOCKET s,

_Out_writes_bytes_to_(len, return) __out_data_source(NETWORK) char FAR * buf,

_In_ int len,

_In_ int flags,

_Out_writes_bytes_to_opt_(*fromlen, *fromlen) struct sockaddr FAR * from,

_Inout_opt_ int FAR * fromlen

);

再看MSDN说明:

If the datagram or message is larger than the buffer specified, the buffer is filled with the first part of the datagram, and recvfrom generates the error WSAEMSGSIZE. For unreliable protocols (for example, UDP) the excess data is lost.

可以看出,buf大小小于UDP包大小的时候,recvfrom()会返回-1,并设置错误WSAEMSGSIZE。

实际编程测试验证确实是这样的表现。

Linux平台的表现

__extern_always_inline ssize_t

recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,

__SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)

可以看出与Windows平台的函数原型相同。但是在其man手册里,没有看到UDP包大于接收缓冲区情况的特殊说明。

写代码测试表明,buf小于UDP包大小的时候,recvfrom()仍然返回复制到缓冲区的字节数,调用者无法得知UDP包被截断的情况。

关于linux udp 接收广播的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux下UDP接收广播的方法 (linux udp 接收广播)