2014-01-22 106 views
1

我寫了一個廣播電臺和一個聽衆其中recvfrom系統上的一個特定端口。我在聽衆中使用了REUSEADDR選項,以使聽衆的多個實例監視同一系統上的相同端口。同一臺機器上的UDP廣播?

當我在不同的機器上運行聽衆,並從另一臺機器發送數據包,所有的聽衆接收包。但是當我在同一臺機器上運行聽衆的多個實例,並且如果我嘗試發送udp數據包,則只有聽衆的第一個實例獲取該數據包不是全部。我想在同一臺機器上廣播UDP數據包,並希望所有偵聽器都能收到數據包。我在Linux上。

我遵循了Beej的指南。

編輯01

監聽器代碼

/* 
** listener.c -- a datagram sockets "server" demo 
*/ 

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

#define MYPORT "4950" // the port users will be connecting to 

#define MAXBUFLEN 100 

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
     if (sa->sa_family == AF_INET) { 
       return &(((struct sockaddr_in*)sa)->sin_addr); 
     } 

     return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

int main(int argc, char *argv[]) 
{ 
     int sockfd; 
     struct addrinfo hints, *servinfo, *p; 
     int rv; 
     int numbytes; 
     struct sockaddr_storage their_addr; 
     char buf[MAXBUFLEN]; 
     socklen_t addr_len; 
     char s[INET6_ADDRSTRLEN]; 

     int reuse_addr = 1; 


     memset(&hints, 0, sizeof hints); 
     hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4 
     hints.ai_socktype = SOCK_DGRAM; 
     hints.ai_flags = AI_PASSIVE; // use my IP 

     if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) { 
       fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
       return 1; 
     } 

     // loop through all the results and bind to the first we can 
     for(p = servinfo; p != NULL; p = p->ai_next) { 
       if ((sockfd = socket(p->ai_family, p->ai_socktype, 
           p->ai_protocol)) == -1) { 
         perror("listener: socket"); 
         continue; 
       } 

       if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 

         if(errno == EADDRINUSE) 
         { 
           if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 
               &reuse_addr, sizeof reuse_addr) < 0) 
             perror("setsockopt(): REUSEADDR\n"),exit(1); 
         } 
         else 
         { 
           close(sockfd); 
           perror("listener: bind"); 
           continue; 
         } 
       } 
       break; 
     } 

     if (p == NULL) { 
       fprintf(stderr, "listener: failed to bind socket\n"); 
       return 2; 
     } 

     freeaddrinfo(servinfo); 

     printf("listener: waiting to recvfrom...\n"); 

     addr_len = sizeof their_addr; 
     if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, 
       (struct sockaddr *)&their_addr, &addr_len)) == -1) { 
       perror("recvfrom"); 
       exit(1); 
     } 

     printf("listener: got packet from %s\n", 
       inet_ntop(their_addr.ss_family, 
         get_in_addr((struct sockaddr *)&their_addr), 
         s, sizeof s)); 
     printf("listener: packet is %d bytes long\n", numbytes); 
     buf[numbytes] = '\0'; 
     printf("listener: packet contains \"%s\"\n", buf); 

     close(sockfd); 

     return 0; 
} 
+0

什麼IP地址是您的發件人發送到?如果它發送到127.0.0.1,那麼它發送單播數據包,並且只有一個監聽器會接收它們。如果它發送到本地網絡的廣播地址(例如,如果您位於192.168.0.x網絡上,則爲192.168.0.255;如果位於10.0.xy網絡上,則爲10.255.255.255等),則所有偵聽器應該收到數據包。 –

+0

我試圖發送到255.255.255.255,本地主機和0.0.0.0。在所有情況下,只有一個聽衆獲得該分組。 – selvakumar

+0

嘗試你局域網的廣播地址(這基本上是你的IP地址按位或不是你的網絡掩碼;例如ip = 192.168.2.5 netmask = 255.255.255.0,broadcast_address =(192.168.2.5 | 0.0.0.255 )= 192.168.2.255 –

回答

0

設置套接字選項SO_REUSEPORT在linstener。

SO_REUSEPORT - 套接字選項允許在同一臺主機上的多個插座綁定到同一個端口

+0

SO_REUSEPORT在linux中不可用,我想當我編譯時,gcc說SO_REUSEPORT是未聲明的 – selvakumar

+0

什麼是操作系統和內核版本? – sujin

+0

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c617f398edd4db2b8567a28e899a88f8f574798d – sujin