2012-06-21 5 views
5

Ich möchte Nachrichten lokal zu vielen Anwendungen senden. Dafür dachte ich, UDP-Sockets seien die beste IPC, korrigiere mich, wenn ich arbeite.Wie sende ich Nachrichten lokal mit UDP-Sockets?

Dazu habe ich folgende Codes verwende:

broadcast:

/* 
** 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; 
} 

Und zu hören:

/* 
** 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; 
} 

Das Problem ist, dass ich IP wie diese 192.168 passieren müssen .1.255 aber im realen Szenario gibt es möglicherweise keine eth0 Schnittstelle, es wird nur Loopback geben. Wie kann ich das erreichen?

Antwort

7

Der Server sollte nicht an eine Adresse gebunden werden, die Sie von getaddrinfo erhalten, stattdessen sollte er an 127.255.255.255 gebunden sein (für die Loopback-Schnittstelle).

Für ein fertiges Beispiel für Broadcast-Server/Client sehen http://www.ccplusplus.com/2011/09/udp-broadcast-client-server-example.html

+0

Ich habe dieses Beispiel viele Male versucht, aber während des Laufens bekomme ich immer 'Erfolg: Schlechte Serveradresse' Und nichts funktioniert :( – Yuvi

3

Unix-Domain-Sockets unterstützen kein Multi-/Broadcasting.

Sie können auf der lokalen Schnittstelle 127.0.0.1 senden.

+0

ja, ich habe gerade dies nach der Veröffentlichung, so habe ich meine Frage bearbeitet .. – Yuvi

+0

aktualisiert, nur lokale Schnittstelle verwenden, die immer vorhanden ist. –

+0

In diesem Fall kann ich nur auf einen Client hören. – Yuvi