在Ubuntu上进行多播

时间:2014-12-12 06:53:25

标签: c linux sockets networking ubuntu-12.04

我的情况如下: 我有一台运行UDP多播服务器的Windows机器正在广播数据包。我编写了一个窗口客户端,能够在连接到网络的单独Windows机器上捕获这些数据包而不会出现问题。我在Windows机器上遇到了一些防火墙问题,但是解决了这个问题。

现在,我有一个ubuntu 12.04版本的客户端;但是,我的程序没有找到这些数据包。我浏览了其他堆栈溢出帖子和一些谷歌线程提供的所有建议:

  1. 当我运行客户端时,netstat -g显示多播网络的IP地址
  2. 我使用sysctl
  3. 将rp_filter设置为0
  4. 使用tcpdump -i wlan0
  5. 时,我可以看到数据包
  6. 添加了一条路线(sudo route add -net 224.0.0.0 netmask 224.0.0.0 wlan0)
  7. 对于第四步,这是通过wlan0建立的无线连接,所以我在wlan0上添加路由。同样,wlan0' rp_filter = 0。

    现在,代码。从打印语句和错误检查。我看到我成功绑定,加入多播组,创建缓冲区等...然后它只是阻塞recvfrom()函数调用。

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <cstring>
    #include <unistd.h>
    #include <pthread.h>
    #include <fstream>
    
    #pragma warning( disable : 4996 )
    
    #define MAX_PACKETSIZE              100000  // max size of packet (actual packet size is dynamic)
    
    bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address);
    void Unpack(char* pData);
    
    #define MULTICAST_ADDRESS       "239.255.42.99"     // IANA, local network
    #define PORT_COMMAND            1510
    #define PORT_DATA               1511                
    #define SOCKET_ERROR -1
    #define INVALID_SOCKET -1
    
    typedef int SOCKET;
    SOCKET DataSocket;
    
    int main(int argc, char* argv[])
    {
        int retval;
        char szMyIPAddress[128] = "";
        in_addr MyAddress, MultiCastAddress;
        int optval = 0x100000;
        int optval_size = 4;
    
    
        // client address
        if(argc>1)
        {
            strcpy(szMyIPAddress, argv[1]); // specified on command line
            IPAddress_StringToAddr(szMyIPAddress, &MyAddress);
        }
        else
        { printf("usage: ./client [local_ip_address]\n"); return 0; }
    
        MultiCastAddress.s_addr = inet_addr(MULTICAST_ADDRESS);   
        printf("Client: %s\n", szMyIPAddress);
        printf("Multicast Group: %s\n", MULTICAST_ADDRESS);
    
        // create a "Data" socket
        printf("Create Socket.\n");
        DataSocket = socket(AF_INET, SOCK_DGRAM, 0);
    
        // allow multiple clients on same machine to use address/port
        int value = 1;
        printf("Set SO_REUSEADDR sockopt.\n");
        retval = setsockopt(DataSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value));
        if (retval == SOCKET_ERROR)
        {
            close(DataSocket);
            return -1;
        }
    
        //bind
        struct sockaddr_in MySocketAddr;
        memset(&MySocketAddr, 0, sizeof(MySocketAddr));
        MySocketAddr.sin_family = AF_INET;
        MySocketAddr.sin_port = htons(PORT_DATA);
        MySocketAddr.sin_addr = MyAddress;
        printf("Bind Socket.\n");
        if (bind(DataSocket, (struct sockaddr *)&MySocketAddr, sizeof(struct sockaddr)) == SOCKET_ERROR)
        {
            printf("[PacketClient] bind failed.\n");
            return 0;
        }
    
        // join multicast group
        struct ip_mreq Mreq;
        Mreq.imr_multiaddr = MultiCastAddress;
        Mreq.imr_interface = MyAddress;
        printf("Join multicast group.\n");
        retval = setsockopt(DataSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&Mreq, sizeof(Mreq));
        if (retval == SOCKET_ERROR)
        {
            printf("[PacketClient] join failed.\n");
            return -1;
        }
    
        // create a 1MB buffer
        printf("Create 1MB Buffer.\n");
        setsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, 4);
        getsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, (socklen_t*)&optval_size);
        if (optval != 0x100000)
        {
            printf("[PacketClient] ReceiveBuffer size = %d\n", optval);
        } 
    
        //listening
        printf("Listening...\n");
        char  szData[20000];
        int addr_len = sizeof(struct sockaddr);
        sockaddr_in TheirAddress;
        while (1)
        {
            // Block until we receive a datagram from the network (from anyone including ourselves)
            int nDataBytesReceived = recvfrom(DataSocket, szData, sizeof(szData), 0, (sockaddr *)&TheirAddress, (socklen_t*)&addr_len);
    
            Unpack(szData);
        }
    
        return 0;
    }
    
    // convert ipp address string to addr
    bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address)
    {
        int retVal;
        struct sockaddr_in saGNI;
        char hostName[256];
        char servInfo[256];
        u_short port;
        port = 0;
    
        // Set up sockaddr_in structure which is passed to the getnameinfo function
        saGNI.sin_family = AF_INET;
        saGNI.sin_addr.s_addr = inet_addr(szNameOrAddress);
        saGNI.sin_port = htons(port);
    
        // getnameinfo
        if ((retVal = getnameinfo((sockaddr *)&saGNI, sizeof(sockaddr), hostName, 256, servInfo, 256, NI_NUMERICSERV)) != 0)
        {
            printf("[PacketClient] GetHostByAddr failed.\n");
            return false;
        }
    
        Address->s_addr = saGNI.sin_addr.s_addr;
    
        return true;
    }
    
    void Unpack(char* pData)
    {
        printf("Begin Packet\n-------\n");
    }
    

    任何建议都表示赞赏。以下是我在尝试解决此问题时用作参考的问题:UDP socket (multicast) not receiving data (Ubuntu)

1 个答案:

答案 0 :(得分:0)

我在这里粘贴我的答案,而不是在评论中写下来。

据我所知,你们两边都有Windows机器,成功播放udp数据包,现在你想用ubuntu机器替换它们。并且机器正在接收数据包,但不会通知您的客户端。

也许这会有所帮助

  

SOL_SOCKET用于套接字层,IPPROTO_IP用于IP层等...对于多播编程,级别始终为IPPROTO_IP

以下是简化的RIPv2协议的工作代码,可以毫无问题地发送和重新发送多播流量。

int setup_sender_connection(struct in_addr interface_addr){
    //create socket
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock<0){
        die("Creating Socket");
    }

    //set outgoing interface
    if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr))<0){
        die("Setting outgoing interface");
    }

    //disable loopback
    u_char loop = 0;
    if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))<0){
        die("Disabling loopback");
    }

    //allow reusing of port
    int reuse = 1;
    if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0){  
        die("Allowing reuse");
    }

    //bind to this port
    struct sockaddr_in saddr;
    bzero(&saddr, sizeof(struct sockaddr_in));

    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(520); 
    saddr.sin_addr = interface_addr;

    if(bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))<0){
        die("Binding");
    }
    return sock;
}

void join_group(int sock, struct in_addr interface_addr){
    //join gorup
    struct ip_mreq mreq;
    bzero(&mreq, sizeof(struct ip_mreq));

    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);    /* IP multicast address of group */
    mreq.imr_interface = interface_addr;            /* local IP address of interface */

    if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))<0){
        die("Joining group");
    }
}

void die(char *error){
    perror(error);
    exit(1);
}