2008-12-12 23 views
12

Tôi đang cố gắng lấy dữ liệu đa hướng udp bằng cách sử dụng ổ cắm và c + + (c). Tôi có một máy chủ với 2 card mạng vì vậy tôi cần phải kết nối socket với giao diện cụ thể. Hiện tại tôi đang thử nghiệm trên một máy chủ khác chỉ có một thẻ mạng.Làm thế nào để thiết lập một ổ cắm cho multicast UDP với 2 card mạng có mặt?

Khi tôi sử dụng INADDR_ANY tôi có thể xem dữ liệu udp, khi tôi liên kết với giao diện cụ thể, tôi không thấy bất kỳ dữ liệu nào. Hàm inet_addr không bị lỗi (bây giờ tôi đã loại bỏ việc kiểm tra giá trị trả về).

Mã dưới đây. Trên máy chủ có một card mạng, địa chỉ IP của tôi là 10.81.128.44. Tôi nhận dữ liệu khi tôi chạy như: ./client 225.0.0.37 12346

này mang lại cho tôi không có dữ liệu: ./client 225.0.0.37 12346 10.81.128.44

Bất kỳ lời đề nghị? (Hy vọng các mã biên dịch, tôi lấy ý kiến ​​...)

#include <stdlib.h> 
    #include <sys/types.h> 
    #include <sys/socket.h> 
    #include <netinet/in.h> 
    #include <arpa/inet.h> 
    #include <time.h> 
    #include <string.h> 
    #include <stdio.h> 

    #include <iostream> 
    #include <string> 

    using namespace std; 

    #define HELLO_PORT 12345 
    #define HELLO_GROUP "225.0.0.37" 
    #define MSGBUFSIZE 256 

    int main(int argc, char *argv[]) 
    { 
     string source_iface; 
     string group(HELLO_GROUP); 
     int port(HELLO_PORT); 

     if (!(argc < 2)) group = argv[1]; 
     if (!(argc < 3)) port = atoi(argv[2]); 
     if (!(argc < 4)) source_iface = argv[3]; 

     cout << "group: " << group << " port: " << port << " source_iface: " << source_iface << endl; 

     int fd; 
     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
     { 
      perror("socket"); 
      exit(1); 
     } 

     u_int yes = 1; 
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) 
     { 
      perror("Reusing ADDR failed"); 
      exit(1); 
     } 

     struct sockaddr_in addr; 
     memset(&addr, 0, sizeof(addr)); 
     addr.sin_family = AF_INET; 
     addr.sin_port = htons(port); 
     addr.sin_addr.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str())); 

    if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0) 
    { 
     perror("bind"); 
     exit(1); 
    } 

    struct ip_mreq mreq; 
    mreq.imr_multiaddr.s_addr = inet_addr(group.c_str()); 
    mreq.imr_interface.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str())); 

    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) 
    { 
     perror("setsockopt"); 
     exit(1); 
    } 

    socklen_t addrlen; 
    int nbytes; 
    char msgbuf[MSGBUFSIZE]; 

    while (1) 
    { 
     memset(&msgbuf, 0, MSGBUFSIZE); 

     addrlen = sizeof(addr); 
     if ((nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *)&addr, &addrlen)) < 0) 
     { 
      perror("recvfrom"); 
      exit(1); 
     } 
     cout.write(msgbuf, nbytes); 
     cout.flush(); 
    } 

    return 0; 
} 

Cảm ơn trước ...

Trả lời

3

Tôi nghĩ rằng bạn cần phải thêm IP_MULTICAST_IF

struct ip_mreq   multi; 

    multi.imr_multiaddr.s_addr = inet_addr(group.c_str()); 
    multi.imr_interface.s_addr = (source_iface.empty() ? 
     htonl(INADDR_ANY): inet_addr(source_iface.c_str())); 

    status = setsockopt(me->ns_fd, IPPROTO_IP, IP_MULTICAST_IF, 
     (char *)&multi.imr_interface.s_addr, 
     sizeof(multi.imr_interface.s_addr)); 

Tôi hy vọng rằng sẽ giúp.

7

Sau khi tìm kiếm và thử nghiệm, tôi phát hiện ra here rằng khi ràng buộc ổ cắm đa hướng udp, chúng tôi chỉ định cổng và địa chỉ để trống, ví dụ: chỉ định INADDR_ANY.

Vì vậy, sau

addr.sin_family = AF_INET; 
addr.sin_port = htons(port); 
addr.sin_addr.s_addr = (source_iface.empty() ? 
         htonl(INADDR_ANY) : 
         inet_addr(source_iface.c_str())); 

nên trông giống như:

COMMENT: Nếu tôi hiểu mã của bạn, bạn nên được liên kết với địa chỉ multicast của bạn không phải là địa chỉ ký tự đại diện. Nếu bạn liên kết với địa chỉ ký tự đại diện, bạn sẽ có thể nhận các gói unicast trên cổng đa hướng của bạn. Việc liên kết với địa chỉ phát đa hướng của bạn sẽ ngăn chặn điều này và đảm bảo bạn chỉ nhận được gói đa hướng trên cổng đó.

EDIT: Cố định mã dựa trên nhận xét trên, liên kết với địa chỉ multicast, lưu trữ trong 'nhóm', như trái ngược với INADDR_ANY chỉ nhận được các gói tin multicast gửi đến địa chỉ multicast.

addr.sin_family = AF_INET; 
addr.sin_port = htons(port); 
addr.sin_addr.s_addr = (group.empty() ? 
         htonl(INADDR_ANY) : 
         inet_addr(group.c_str())); 

Điều này giải quyết được vấn đề. Thêm IP_MULTICAST_IF sẽ không hữu ích vì đó là để chọn giao diện cụ thể để gửi dữ liệu udp, vấn đề ở trên là ở bên nhận.

+0

Nếu tôi hiểu mã của bạn, bạn phải ràng buộc với địa chỉ phát đa hướng của mình chứ không phải địa chỉ ký tự đại diện. Nếu bạn liên kết với địa chỉ wildcard, bạn sẽ có thể nhận các gói unicast trên cổng multicast của bạn. Việc liên kết với địa chỉ multicast của bạn sẽ ngăn chặn điều này và đảm bảo bạn chỉ nhận được các gói multicast trên cổng đó. –

+0

Quyền của bạn, tôi đã thực sự thấy rằng trong một thời gian trước đây, chỉ cần không cập nhật câu trả lời ở đây. Cảm ơn, tôi đã cập nhật mã. – stefanB

Các vấn đề liên quan