我运行下面的服务器代码打开UDP套接字。我的linux机器上有两个网络接口,两个接口连接到两个不同的网络。我希望程序能够监听指定的网络(通过分配IP地址),因此我在UDP套接字上分配了一个IP地址。
如果我使用servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
,服务器可以接收广播和单播消息。但是,如果我定义servaddr.sin_addr.s_addr =inet_addr("10.0.0.6");
,那么服务器可以接收发送到10.0.0.6
的消息,但无法接收广播10.0.0.255
消息(网络掩码 / 24 ) 。
here是广播消息的代码,单播代码为here。
我是否错误地分配了IP地址或者广播代码是错误的?
服务器代码是:
#define BUFSIZE 512
char *SERVER_IP = "10.0.0.6";
int main() {
int error_count=0, r=0, n=0;
int sockfd = 0;
struct sockaddr_in servaddr, cliaddr ,a ;
socklen_t len; //integer type of width of at least 32 bits
char mesg[1000];
sockfd = socket(AF_INET, SOCK_DGRAM, 0); // for datagram
while(sockfd < 0){ //error handling for socket opening
usleep(500000);
if (++error_count == 20){//10 times itteration
fprintf(stderr, "errno:%s - socket opening error - line 223\n ", strerror(errno));
exit(1);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
}
error_count = 0;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(33333); //server listens on this port
// servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr =inet_addr(SERVER_IP);
printf("servaddr.sin_addr:%lu\n",servaddr.sin_addr );
printf("a.sin_addr:%lu\n",a.sin_addr );
r = bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
while(r < 0){ //error handling for socket binding
usleep(500000);
if (++error_count == 20){//10 times itteration
fprintf(stderr, "errno:%s - socket binding error - line 239\n ", strerror(errno));
exit(1);
}
r = bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
}
error_count = 0;
while(1){
len = sizeof(cliaddr);
next:
printf("server is listening\n");
n = recvfrom(sockfd, mesg, 1000, 0, (struct sockaddr *) &cliaddr, &len);
printf("line195: packet is received: %s\n", mesg);
if(n < 0){
fprintf(stderr, "recvfrom error occured - line254\n");
n = 0;
goto next;
}
}
return 0;
}
这是我的ifconfig -a wlan8
wlan8 Link encap:Ethernet HWaddr 64:70:02:18:1f:b6
inet addr:10.0.0.6 Bcast:10.0.0.255 Mask:255.255.255.0
inet6 addr: fe80::6670:2ff:fe18:1fb6/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:206 errors:0 dropped:0 overruns:0 frame:0
TX packets:297 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:37857 (37.8 KB) TX bytes:54526 (54.5 KB)
答案 0 :(得分:2)
您可以通过INADDR_ANY
并正确调用setsockopt
让您的服务器正常工作。
应该是这样的,就在套接字创建之后:
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "wlan8");
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
(void *)&ifr, sizeof(ifr)) < 0) {
fprintf(stderr, "error at setsockopt, ensure it is running as root.\n");
exit(1);
}
显然,您还必须#include <net/if.h>
并在struct ifreq ifr;
的开头定义main
。
这样,您的服务器将收到针对wlan8
接口的任何地址(广播和单播)的每个数据报,但它将忽略其他接口。
SO_BINDTODEVICE
,但需要root权限。您可以使用sudo
或从root执行以下命令来设置SUID(因此您可以通过组关联控制程序执行)
chmod 4750 server_name
显然你应该小心这类程序,否则你会在你的系统中打开安全漏洞。
最后我建议你阅读
答案 1 :(得分:1)
你没有做错任何事。除非套接字绑定到广播地址或INADDR_ANY,否则Linux不会接收广播数据报。您需要将一个套接字绑定到单播地址,将另一个套接字绑定到广播地址,或者如果绑定到INADDR_ANY,则可以使用IP_PKTINFO查找目标地址。在Get destination address of a received UDP packet处有一些示例代码。
答案 2 :(得分:0)
如果您只想听接口wlan8
,请尝试收听整个网络 - 在这种情况下为10.0.0.0
。如果绑定到接口的IP,它可能只接收带有它作为目标的消息。