2012-06-21 64 views
5

我想在本地向许多应用程序广播消息。为此我认为UDP套接字是最好的IPC,纠正我,如果我worng。如何在本地使用UDP套接字广播消息?

为此,我现在用的是以下代码:

对于广播:

/* 
** broadcaster.c -- a datagram "client" that can broadcast 
*/ 

#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 SERVERPORT 4950 // the port users will be connecting to 

int main(int argc, char *argv[]) 
{ 
    int sockfd; 
    struct sockaddr_in their_addr; // connector's address information 
    struct hostent *he; 
    int numbytes; 
    int broadcast = 1; 
    //char broadcast = '1'; // if that doesn't work, try this 

    if (argc != 3) { 
     fprintf(stderr,"usage: broadcaster hostname message\n"); 
     exit(1); 
    } 

    if ((he=gethostbyname(argv[1])) == NULL) { // get the host info 
     perror("gethostbyname"); 
     exit(1); 
    } 

    if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { 
     perror("socket"); 
     exit(1); 
    } 

    // this call is what allows broadcast packets to be sent: 
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, 
     sizeof broadcast) == -1) { 
     perror("setsockopt (SO_BROADCAST)"); 
     exit(1); 
    } 

    their_addr.sin_family = AF_UNIX;  // host byte order 
    their_addr.sin_port = htons(SERVERPORT); // short, network byte order 
    their_addr.sin_addr = *((struct in_addr *)he->h_addr); 
    memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero); 

    if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0, 
      (struct sockaddr *)&their_addr, sizeof their_addr)) == -1) { 
     perror("sendto"); 
     exit(1); 
    } 

    printf("sent %d bytes to %s\n", numbytes, 
     inet_ntoa(their_addr.sin_addr)); 

    close(sockfd); 

    return 0; 
} 

,并听取:

/* 
** 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(void) 
{ 
    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 optval = 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(setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, &optval, sizeof optval) != 0) 
     { 
      perror("listener: setsockopt"); 
      continue; 
     } 

     if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
      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; 
} 

的问题是,我必须通过IP这样192.168 .1.255但在真实场景中可能没有eth0接口,只会有环回。那我怎么能做到这一点?

回答

7

服务器不应该绑定到从getaddrinfo获得的地址,而应该绑定到127.255.255.255(用于回送接口)。

对于广播服务器的一个现成的例子/客户端看到http://www.ccplusplus.com/2011/09/udp-broadcast-client-server-example.html

+0

我已经试过这个例子很多次,但在运行时,我总是得到'成功:服务器地址错误'并没有任何工作:( – Yuvi

3

Unix域套接字不支持多/广播。

您可以在本地接口127.0.0.1上进行广播。

+0

是的,我刚刚发现这个张贴后,我已经编辑我的问题.. – Yuvi

+0

更新,只需要使用始终存在本地接口。 –

+0

在这种情况下,我只能听一个客户端。 – Yuvi