2017-02-22 98 views
2

在我的Ubuntu 16.04系統我跑到下面的程序:如何從已訂閱的組接收組播數據包?

#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> 


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

main(int argc, char *argv[]) 
{ 
    struct sockaddr_in addr; 
    int fd, nbytes,addrlen; 
    struct ip_mreq mreq; 
    char msgbuf[MSGBUFSIZE]; 

    u_int yes=1;   

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

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

    memset(&addr,0,sizeof(addr)); 
    addr.sin_family=AF_INET; 
    addr.sin_addr.s_addr=inet_addr(HELLO_GROUP); 
    addr.sin_port=htons(HELLO_PORT); 

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

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

這個程序只是訂閱我的系統從組225.0.0.37

接收多播UDP數據包在其他系統上的我的本地網絡我有另一個程序,其週期性地發送分組到該組

使用上述程序我確認我收到從Wireshark的註定225.0.0.37 UDP包訂閱所述組後

我想通過另一個程序讀取這些傳入數據包。我不想使用原始套接字。以下是我寫的其他程序:

#include <iostream> 
#include <boost/array.hpp> 
#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/lexical_cast.hpp> 

using boost::asio::ip::udp; 

static const int max_length = 1024; 

char data_[max_length]; 

void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd) 
{ 
    std::cout.write(data_, bytes_recvd); 
} 

int main(int argc, char* argv[]) 
{ 
    try 
    { 

    boost::asio::io_service io_service; 

    udp::endpoint local_endpoint = boost::asio::ip::udp::endpoint(
     boost::asio::ip::address::from_string("225.0.0.37"), boost::lexical_cast<int>("12345")); 
    std::cout << "Bind " << local_endpoint << std::endl; 

    udp::socket socket(io_service); 
    socket.open(local_endpoint.protocol()); 
    socket.set_option(udp::socket::reuse_address(true)); 
    socket.bind(local_endpoint); 

    socket.async_receive(
     boost::asio::buffer(data_, max_length), 
     boost::bind(&handle_receive_from, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 

    io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
    std::cerr << e.what() << std::endl; 
    } 

    return 0; 
} 

這個方案沒有得到任何數據,即使我看到通過Wireshark的到來包。我究竟做錯了什麼?獲得數據甚至可能嗎? 總體問題是這樣的:我可以在一個程序中訂閱多播組並在另一個程序中接收數據包?

回答

1

這取決於。

如果你的第一個程序即將退出,那麼os會關閉套接字,發送IGMP Leave,這樣你的第二個程序就不會收到任何多點傳送數據包。所以你應該保持第一個程序運行(添加一個函數永遠阻塞),以便它不離開多播組。

實際上,linux內核跟蹤每個套接字的組成員資格,似乎它沒有使用它來過濾多播數據包。因此,您可以在一個程序中訂閱多播組,並在另一個程序中接收數據包,直到取消訂閱(適用於我的Ubuntu 14.04)。不知道這個策略是否會改變,但在我的OS X 10.10上,它不允許這樣的事情。