2012-06-21 14 views
5

Quiero transmitir mensajes localmente a muchas aplicaciones. Por eso pensé que los sockets UDP son los mejores IPC, corrígeme si estoy cansado.¿Cómo se transmite un mensaje usando sockets UDP localmente?

Para ello estoy usando los siguientes códigos:

Para su difusión:

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

y escuchar:

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

El problema es que tengo que pasar IP como esto 192.168 .1.255 pero en el escenario real no puede haber interfaz eth0, solo habrá loopback. Entonces, ¿cómo puedo lograr esto?

Respuesta

7

El servidor no se debe vincular a una dirección que se obtiene de getaddrinfo, sino que debe estar vinculado a 127.255.255.255 (para la interfaz de bucle invertido).

Para un ejemplo confeccionada de servidor de difusión/cliente a ver http://www.ccplusplus.com/2011/09/udp-broadcast-client-server-example.html

+0

He intentado ese ejemplo muchas veces, pero durante la ejecución siempre obtengo 'Éxito: mala dirección del servidor' Y nada funciona :( – Yuvi

3

Los sockets de dominio Unix no son compatibles con multi-/broadcasting.

Puede transmitir en la interfaz local 127.0.0.1.

+0

sí, acabo de encontrar esto después de publicar, por lo que he editado mi pregunta .. – Yuvi

+0

Actualizado, sólo tiene que utilizar la interfaz local que siempre existe. –

+0

En este caso, puedo escuchar solo en un cliente. – Yuvi

Cuestiones relacionadas