UDP的socket绑定到IP地址后无法接受广播数据

由于考虑到我的程序要在多网卡的机器上运行,所以我将网卡的ip地址绑定到了socket
server_addr.sin_addr.s_addr = inet_addr(servIP);但是这样就无法收到广播数据?同时我也绑定到了一个广播地址接受时发现没次客户端来的数据都连续接受两次;请问是为什么?

以下是我的测试程序:

//server.cpp
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>

char * host_name = "192.168.0.255";
int port = 10051;

int main(void)
{
struct sockaddr_in serv_addr,addr;
char buf[256];

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("Error: socket";
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(host_name);//htonl(INADDR_ANY);//

int bd = bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
while(1)
{
int len = sizeof(serv_addr);
memset(&serv_addr, 0, len);
int ret = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serv_addr,(socklen_t*)&len);
printf("recv=%d buf=%s
",ret, buf);
printf("RecvieIP:%s Recive Port:%d
", inet_ntoa(serv_addr.sin_addr),
ntohs(serv_addr.sin_port));
ret = sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr_in));
}

}


//client.cpp

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>

char * host_name = "192.168.0.255";

int port = 10051;
int main(void)
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("Error: socket";
return -1;
}

struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr(host_name);
int so_broadcast;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &so_broadcast,
sizeof(so_broadcast));

char buf[256]="client .............";
sockaddr from ;
int len;
sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr_in));
while(1)
{
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serv_addr,(socklen_t*)&len);
printf("server buf= %s
",buf);
}
}
嗯, bind到网卡地址是不能接收广播包的

那你就别 bind了呗

udp广播的递送规则是:
如果没有设置BLOADCASE选项的不递送。
如果 bind端口不匹配不递送该套接口
如果绑定的不是INADDR_ANY话
那么必须 BIND的地址和目的地址匹配才能递送:
也就是说你必须 BIND一个广播地址或者绑定INADDR_ANY
第三
如果你的udp调用了connect
那么源地址和源端口不匹配也不递送
否则递送

你可以设置其中一个网卡DISABLE广播能力
.
fannyth
05-11-11, 13:36
看来我要重新考虑解决我问题的思路;我把问题再说一遍,大家看看有什么好的思路来解决。

由于考虑到我的程序要在多网卡的机器上运行,所以我希望socket既能接受广播的数据又能接受单播的数据。同时在接受广播数据时只接受一次。因为服务器是多网卡的;而我的客户端在启动时还不知道自己的ip地址;所以客户端发送的广播地址是255.255.255.255;所以我想是否可以用两个soket一个用来接受广播,同时自动进行包过虑。另一个用来接受单播数据?不知这样可以吗?会不会有什么影响?
Westwind
05-11-11, 14:04
你可以这样做。

2个udp socket
单播的那个socket bind INADDR_ANY并且设置SO_BROADCAST选项为0,此时他只接受单播数据报

广播那个socket bind 255.255.255.255,并且设置SO_BROADCASE选项为1,此时他只接受UDP广播。

为了防止接收到同一个广播的2分copy,如果两个网卡位于同一个子网,那么就用ifconfig命令disable其中一块网卡的BROADCAST标志,让其不能接受以太网广播。

你也可以使用ioctl的SIOCSIFFLAGS方法去掉一个接口的标志IFF_BROADCAST,使之不能接受以太网广播
Westwind
05-11-12, 00:27
谢谢,你说的很详细了,我可以试试;但我想如果设置另一块网卡不能接受广播数据,是否会对其它程序有影响?所以我想能自己在接受广播数据的同时做一个检测,检测收到的数据是否是指定网卡接受到的如果是则处理,否则丢弃;但不知道如何检测?同时对效率的影响有多大?

这个也有可能,至少存在一个socket api可以返回数据报的目的地址,
recvmsg
recvmsg是非SVR4系统的recv,recvfrom,readv的底层实现,在recvmsg之下就是syscall了。
不过这个函数挺复杂的,你需要学习该函数的用法,并且该函数是不可移植的,至少windows不提供该方法。

你可能感兴趣的:(windows,server,socket,struct,api,服务器)