2017-08-17 60 views
1

我有一個真正的時間熊試圖瞭解IP多播。特別是,我想禁止將數據包循環回多播組。禁止UDP多播的自我接收

我剛把這段代碼放在一起,舉例說明了我所看到的。

/* 

example.c 

*/ 

#include <sys/types.h> 

#include <net/if.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

#include <pthread.h> 
#include <time.h> 
#include <string.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <stdio.h> 

#define EXAMPLE_PORT 6000 
#define EXAMPLE_GROUP "224.0.0.1" 

const long MYSENDER = 0; // send thread ID 
const long MYRECVR = 1; // recv thread ID 

int status; 
int sock; 

void *sender(void *threadid); 
void *receiver(void *threadid); 

main(int argc) { 
    pthread_t threads[2]; 
    struct sockaddr_in addr; 

    /* Set up socket */ 
    sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 
    if (sock == -1) { 
     perror("socket"); 
     exit(1); 
    } 

    status = pthread_create(&threads[MYRECVR], NULL, receiver, (void *) MYRECVR); // Start the server thread and check for error 
    if (status) { 
     fprintf(stderr, "Error: pthread_create(receiver) returned %d\n", status); 
     exit(-1); 
    } 

    status = pthread_create(&threads[MYSENDER], NULL, sender, (void *) MYSENDER); // Start the client thread and check for error 
    if (status) { 
     fprintf(stderr, "Error: pthread_create(sender) returned %d\n", status); 
     exit(-1); 
    } 

    pthread_join(threads[MYRECVR], NULL); // main() will wait for the server thread to complete 
    pthread_join(threads[MYSENDER], NULL); // main() will wait for the client thread to complete 
} 

void *sender(void *threadid) { 
    int c; 
    char message[50]; 
    struct sockaddr_in addr; 
    int addrlen, cnt; 

    memset((char *) &addr, 0, sizeof (addr)); 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP); 
    addr.sin_port = htons(EXAMPLE_PORT); 
    addrlen = sizeof (addr); 

    fprintf(stderr, "Starting sender thread!\n"); 

    /* Send */ 
    while (1) { 
     time_t t = time(0); 
     sprintf(message, "time is %-24.24s", ctime(&t)); 
     printf("sending: %s\n", message); 
     cnt = sendto(sock, message, sizeof (message), 0, 
       (struct sockaddr *) &addr, addrlen); 
     if (cnt < 0) { 
      perror("sendto"); 
      exit(1); 
     } 
     sleep(5); 
    } 
    return 0; 
} 

void *receiver(void *threadid) { 
    int opt = 1; 
    char message[50]; 
    struct sockaddr_in addr; 
    int addrlen, cnt; 
    struct ip_mreq mreq; 

    fprintf(stderr, "Starting receiver thread!\n"); 

    memset((char *) &addr, 0, sizeof (addr)); 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    addr.sin_port = htons(EXAMPLE_PORT); 
    addrlen = sizeof (addr); 


    /* Receive */ 

    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); 
    if (bind(sock, (struct sockaddr *) &addr, sizeof (addr)) < 0) { 
     perror("bind"); 
     exit(1); 
    } 

    mreq.imr_multiaddr.s_addr = inet_addr(EXAMPLE_GROUP); 
    mreq.imr_interface.s_addr = htonl(INADDR_ANY); 
    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
      &mreq, sizeof (mreq)) < 0) { 
     perror("setsockopt mreq"); 
     exit(1); 
    } 

    while (1) { 
     cnt = recvfrom(sock, message, sizeof (message), 0, 
       (struct sockaddr *) &addr, &addrlen); 
     if (cnt < 0) { 
      perror("recvfrom"); 
      exit(1); 
     } else if (cnt == 0) { 
      break; 
     } 
     printf("%s: message = \"%s\"\n", inet_ntoa(addr.sin_addr), message); 
    } 
    return 0; 
} 

它運行良好,併產生下列輸出...

[email protected]:/tmp$ ./test 
Starting receiver thread! 
Starting sender thread! 
sending: time is Wed Aug 16 19:23:29 2017 
10.249.27.51: message = "time is Wed Aug 16 19:23:29 2017" 
sending: time is Wed Aug 16 19:23:34 2017 
10.249.27.51: message = "time is Wed Aug 16 19:23:34 2017" 
^C 
[email protected]:/tmp$ 

但是,我想,以防止在被環回郵件......

+0

你需要調查'setsockopt的()'用'IP_MULTICAST_LOOP'選項。 – EJP

+0

我應該提到我確實使用了setsockopt()來禁用IP_MULTICAST_LOOP,但是數據包仍然被循環回去。 –

+0

您當然應該,而且您還應該包含相關的代碼。這可能不正確。 – EJP

回答

1

默認情況下,最操作系統會將輸出的多播流量循環回本地機器。如果要禁用此行爲,您需要將IP_MULTICAST_LOOP套接字選項設置爲0。

​​