Linux Socket详解 <七> UDP广播
(2015-03-11 11:02:04)
标签:
linuxsocketbroadcastudp |
分类: linux |
作者: Sam (甄峰) sam_code@hotmail.com
之前谈到UDP可以发送广播,这里就讨论下UDP广播。
0. 广播的应用:
在某个子网内,有一台特定设备,但我们不清楚这台设备的地址,可以通过发送UDP广播,设备接收到此特定广播后回复。则可以得到设备的地址。
频繁的广播会加大网络负载,因为它会发送数据到每个地址。
1. 广播地址:
IP地址由两部分组成,NetID(网络地址)和HostID(主机地址)。
网络掩码用于把网络地址从IP地址中提取出来。
IP地址与网络掩码按位相与。则得到网络地址。
HostID每个bit置1. 则此IP即为网络内广播地址。
例如:
IP: 192.168.0.2. MASK:
255.255.255.0
则广播地址:192.168.0.255
IP: 172.16.0.2 MASK: 255.255.0.0
广播地址:172.16.255.255
ifconfig中,会显示广播地址信息:
inet 10.0.0.2 netmask 255.255.255.0
broadcast 10.0.0.255
Sam认为这样说比较合适:
当向广播地址的某个端口发送数据报时,即相当于向本网内每个设备的这个端口发送数据报。
2. 发送广播消息:
要发送广播消息,需要两个基本条件。
a. 建立的socket 激活SO_BROADCAST选项。使socket
endpoint成为一个可发送广播的socket.
b. 利用sendto(2) 向广播地址的特定port发送数据报。
也就是说:这个socket 必须能够进行广播。且目的地址必须为一个广播地址。
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char** argv)
{
int iSocket_Send = 0;
int iRet = 0;
static int so_broadcast = 1;
char ip_Server[16] = {0};
struct sockaddr_in addr_server;
struct sockaddr_in addr_broadcast;
uint16_t port = 0;
char Message[36] = "Air raid this is not a drill";
iSocket_Send = socket(PF_INET, SOCK_DGRAM, 0);
if(iSocket_Send == -1)
{
perror("socket()");
return -1;
}
iRet = setsockopt(iSocket_Send, SOL_SOCKET, SO_BROADCAST,
&so_broadcast, sizeof(so_broadcast));
if(iRet == -1)
{
perror("setsockopt()");
return -1;
}
memset(&addr_server, 0, sizeof(struct sockaddr_in));
strcpy(ip_Server, "10.0.0.2");
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(port);
inet_aton(ip_Server, (struct in_addr
*)&addr_server.sin_addr);
#if 0
iRet = bind(iSocket_Send, (const struct sockaddr
*)&addr_server, sizeof(struct sockaddr_in));
if(iRet == -1)
{
perror("bind()");
return -1;
}
#endif
memset(&addr_broadcast, 0, sizeof(struct
sockaddr_in));
strcpy(ip_Server, "10.0.0.255");
addr_broadcast.sin_family = AF_INET;
addr_broadcast.sin_port = htons(9090);
inet_aton(ip_Server, (struct in_addr
*)&addr_broadcast.sin_addr);
for(;;)
{
sendto(iSocket_Send, Message, strlen(Message), 0, (const
struct sockaddr *)&addr_broadcast, sizeof(struct
sockaddr_in));
sleep(1);
}
return 0;
}
3. 接收广播消息:
理论上,接收广播消息和接收通常的UDP消息不应该有不同。就是接收指定Port上的数据。
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char** argv)
{
int iSocket_Send = 0;
int iRet = 0;
uint16_t port = 9090;
struct sockaddr_in addr_local;
struct sockaddr_in addr_server;
char buffer[256] = {0};
socklen_t addr_len = 0;
iSocket_Send = socket(PF_INET, SOCK_DGRAM, 0);
if(iSocket_Send == -1)
{
perror("socket()");
return -1;
}
memset(&addr_local, 0, sizeof(struct sockaddr_in));
addr_local.sin_family = AF_INET;
addr_local.sin_port = htons(port);
addr_local.sin_addr.s_addr = htonl(INADDR_ANY);
iRet = bind(iSocket_Send, (const struct sockaddr
*)&addr_local, sizeof(struct sockaddr_in));
if(iRet == -1)
{
perror("bind()");
return -1;
}
for(;;)
{
memset(buffer, 0, 256);
memset(&addr_server, 0, sizeof(struct sockaddr_in));
addr_len = sizeof(struct sockaddr_in);
iRet = recvfrom(iSocket_Send, buffer, 256, 0, (struct sockaddr
*)&addr_server, &addr_len);
if(iRet == -1)
{
perror("recvfrom()");
continue;
}
printf("\nReceive Message from : [%s:%d].\n",
inet_ntoa(addr_server.sin_addr),
ntohs(addr_server.sin_port));
printf("\nMessage:[%s]. length:[%d]\n", buffer, iRet);
}
return 0;
}
但看了不少例子,在接收端,它是把广播地址绑定到接收socket上去。待未来研究。