Come per la trasmissione di un Messaggio, utilizzando socket UDP a livello locale?

Voglio trasmettere messaggi in locale di molte applicazioni. Per questo ho pensato socket UDP è il miglior DAC, mi corregga se sto worng.

Per questo sto utilizzando i seguenti codici:

Per la trasmissione:

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

E ascoltare :

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

Il problema è che devo passare IP come questo 192.168.1.255 ma il vero scenario potrebbe non essere interfaccia eth0, ci sarà solo il loopback. Quindi come posso realizzare questo?

InformationsquelleAutor Yuvi | 2012-06-21

3 Replies
  1. 4

    Socket di dominio Unix non supporta il multi-/diffusione.

    È possibile trasmettere sull’interfaccia locale 127.0.0.1.

    sì, ho appena trovato questo dopo la pubblicazione, così ho modificato la mia domanda..
    Aggiornato, basta usare interfaccia locale che esiste sempre.
    In questo caso, sono in grado di ascoltare in un solo client.
    Multi-avviare un’interfaccia locale, in modo che più di un client riceve il datagramma.
    qualsiasi link di riferimento sarebbe utile.. 🙂

    InformationsquelleAutor Maxim Egorushkin

  2. 0

    Mentre la domanda originale non esplicitamente dirlo, credo che l’originale asker ha voluto ‘broadcast’ di più applicazioni in esecuzione sullo stesso sistema operativo istanza (stesso computer vecchio timer).

    Questo è supportato dall’utilizzo di ‘SO_REUSEADDR’ nell’ascoltatore esempio, e di follow-up commenti Yuvi, e, infine, un suggerimento per l’utilizzo di IP multicast.

    L’originale della domanda deve essere chiarito.

    Credo pacchetto di distribuzione con più di leganti su una singola porta UDP varia tra i sistemi operativi quando si utilizza SO_REUSEADDR.
    La mia esperienza recente di Windows, è che un singolo ‘binder’ è esclusivamente dato tutti i pacchetti fino a quando esce il bind, momento in cui, un altro raccoglitore è scelto e presentato tutti i pacchetti ricevuti, fino a quando lei comunicati, e così via…

    Questo a quanto pare è diverso dal kernel Linux recenti, come spiegato in questo link: https://stackoverflow.com/a/14388707/86375
    Che viene visualizzata la pagina di rivendicare Linux round-robin riceve i pacchetti tra più di leganti.

    Il risultato finale, se si spera di inviare-a-molti utilizzando un unico mandato-i datagrammi del poster originale ha fatto, e si tenta di utilizzare IP unicast, non multicast IP, si può essere delusi.
    (La mia esperienza, e il link qui sopra mostra multi-bind, ma che non implica multi-consegna dei datagrammi ricevuti, né su Linux o Windows)

    Il poster originale dovrebbe avere provato ad utilizzare multicast.

    InformationsquelleAutor Cameron

Lascia un commento