Проблемы с UDP-multicast
От: yourSensey  
Дата: 22.07.11 13:26
Оценка:
Только начал разбираться с работой udp-multicast. Под это есть задача написать небольшое приложение, подключающееся к multicast-группе и получающее с сервера данные.
Программа в целом написана. Она без проблем присоединяется к мулькаст-группе и сервер даже начинает слать данные(это видно в снифере Wireshark, мониторящем трафик на данной машине).

Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.

В чём может быть проблема? Может быть, требуется дополнительная настройка OC?

Код написан в MS VC2010 с Winsock2. ОС на тестируемой машине — Windows Server 2008 SP2.

Собственно код клиента:

    #ifndef UNICODE
    #define UNICODE
    #endif
    #define WIN32_LEAN_AND_MEAN
    #include <winsock2.h>
    #include <Ws2tcpip.h>
    #include <stdio.h>
    #include <mswsock.h>
     
    // Link with ws2_32.lib
    #pragma comment(lib, "Ws2_32.lib")
    #define u_int32 UINT32  // Unix uses u_int32
     
    #define RECV_IP_ADDR    "224.5.5.13"    // arbitrary multicast address
    #define MY_IP_ADDR      "192.168.1.2"   //
     
    int                  /* OUT: whatever setsockopt() returns */
    join_source_group(int sd, u_int32 grpaddr,
       u_int32 srcaddr, u_int32 iaddr)
    {
       struct ip_mreq_source imr;
       memset(&imr, 0, sizeof(imr));
     
       imr.imr_multiaddr.s_addr  = grpaddr;
       imr.imr_sourceaddr.s_addr = srcaddr;
       imr.imr_interface.s_addr  = iaddr;
       return setsockopt(sd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *) &imr, sizeof(imr));
    }
     
    int
    leave_source_group(int sd, u_int32 grpaddr,
       u_int32 srcaddr, u_int32 iaddr)
    {
       struct ip_mreq_source imr;
     
       imr.imr_multiaddr.s_addr  = grpaddr;
       imr.imr_sourceaddr.s_addr = srcaddr;
       imr.imr_interface.s_addr  = iaddr;
       return setsockopt(sd, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, (char *) &imr, sizeof(imr));
    }
     
    int main(int argc, char * argv[])
    {
        if (argc < 3)
        {
            wprintf(L"Need a server IP and your local IP\n");
            return 1;
        }
        char recvIpAddr[16] = RECV_IP_ADDR;
        char myIpAddr[16] = MY_IP_ADDR;
        strncpy(recvIpAddr, argv[1], 15);
        strncpy(myIpAddr, argv[2], 15);
     
        int iResult = 0;
     
        WSADATA wsaData;
     
        SOCKET RecvSocket;
        sockaddr_in RecvAddr;
     
        char RecvBuf[1024];
        int BufLen = 1024;
     
        sockaddr_in SenderAddr;
        int SenderAddrSize = sizeof(SenderAddr);
        memset(&SenderAddr, 0, SenderAddrSize);
     
        //-----------------------------------------------
        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != NO_ERROR) {
            wprintf(L"WSAStartup failed with error %d\n", iResult);
            return 1;
        }
        //-----------------------------------------------
        // Create a receiver socket to receive datagrams
        RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (RecvSocket == INVALID_SOCKET) {
            wprintf(L"socket failed with error %d\n", WSAGetLastError());
            return 1;
        }
     
        int one = 1;
        if ( setsockopt(RecvSocket, IPPROTO_IP, SO_REUSEADDR, (char *)&one, sizeof(one)) == SOCKET_ERROR)
        {
        wprintf(L"Error setting SO_REUSEADDR!");
        return 1;
        }
     
        //-----------------------------------------------
        // Bind the socket to any address and the specified port.
        volatile unsigned short Port = 61000;
     
        memset(&RecvAddr, 0, sizeof(RecvAddr));
        RecvAddr.sin_family = AF_INET;
        RecvAddr.sin_port = htons(61000);
        RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
     
        iResult = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
        if (iResult != 0) {
            wprintf(L"bind failed with error %d\n", WSAGetLastError());
            return 1;
        }
     
        join_source_group(RecvSocket, inet_addr(recvIpAddr), inet_addr(myIpAddr), INADDR_ANY);
     
        //-----------------------------------------------
        // Call the recvfrom function to receive datagrams
        // on the bound socket.
        wprintf(L"Receiving datagrams...\n");
        while (1)
        {
        iResult = recvfrom(RecvSocket, RecvBuf, BufLen, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);
     
        if (iResult == SOCKET_ERROR) {
            wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
        }
        RecvBuf[iResult] = 0;
        printf("recvfrom %s\n", RecvBuf);
        }
     
        //-----------------------------------------------
        // Close the socket when finished receiving datagrams
        wprintf(L"Finished receiving. Closing socket.\n");
        iResult = closesocket(RecvSocket);
        if (iResult == SOCKET_ERROR) {
            wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
            return 1;
        }
     
        //-----------------------------------------------
        // Clean up and exit.
        wprintf(L"Exiting.\n");
        WSACleanup();
        return 0;
    }
multicast winsock2
Re: Проблемы с UDP-multicast
От: MescalitoPeyot Украина  
Дата: 23.07.11 11:30
Оценка:
Здравствуйте, yourSensey, Вы писали:

S>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.


А если попробовать заменить IP_ADD_SOURCE_MEMBERSHIP на IP_ADD_MEMBERSHIP? Плюс еще можно попробовать заменить imr.imr_interface.s_addr с конкретного адреса на IP_ANY_ADDR (0.0.0.0)
Re: Проблемы с UDP-multicast
От: MKM  
Дата: 23.07.11 11:45
Оценка:
S>Только начал разбираться с работой udp-multicast. Под это есть задача написать небольшое приложение, подключающееся к multicast-группе и получающее с сервера данные.
S>Программа в целом написана. Она без проблем присоединяется к мулькаст-группе и сервер даже начинает слать данные(это видно в снифере Wireshark, мониторящем трафик на данной машине).
Что значит данная машина?
Машина, где запущен сервер или запущен клиент?
На всех маршрутизаторах между клиентом и сервером включена поддержка мультикаста?
Если клиент и ваш сервер запускать на разных машинах, то рассылка приходит?

S>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.


S>В чём может быть проблема? Может быть, требуется дополнительная настройка OC?

S>Код написан в MS VC2010 с Winsock2. ОС на тестируемой машине — Windows Server 2008 SP2.
Может быть это будет полезно (если используется впн):
http://support.microsoft.com/kb/981637
Re: Проблемы с UDP-multicast
От: sand7e Россия  
Дата: 25.07.11 09:18
Оценка:
Здравствуйте, yourSensey

подпишись на группу на стороне клиента
см IP_ADDMEMBERSHIP
Re[2]: Проблемы с UDP-multicast
От: yourSensey  
Дата: 25.07.11 09:30
Оценка:
Здравствуйте, sand7e, Вы писали:

S>подпишись на группу на стороне клиента

S>см IP_ADDMEMBERSHIP

На группу подписан. См код join_source_group()
Re[2]: Проблемы с UDP-multicast
От: yourSensey  
Дата: 25.07.11 09:40
Оценка:
Здравствуйте, MKM, Вы писали:

S>>Только начал разбираться с работой udp-multicast. Под это есть задача написать небольшое приложение, подключающееся к multicast-группе и получающее с сервера данные.

S>>Программа в целом написана. Она без проблем присоединяется к мулькаст-группе и сервер даже начинает слать данные(это видно в снифере Wireshark, мониторящем трафик на данной машине).
MKM>Что значит данная машина?
MKM>Машина, где запущен сервер или запущен клиент?
MKM>На всех маршрутизаторах между клиентом и сервером включена поддержка мультикаста?
MKM>Если клиент и ваш сервер запускать на разных машинах, то рассылка приходит?
Данная машина — комп, на котором запускается клиент(и иногда мой сервер).
Да, поддержка мультикаста включена на всём пути между тестовой машиной и сервером(multicast-трафик отправляется и приходит на тестовый комп, как показывает там же запущенный снифер).
Пробовал запускать мои клиент и сервер с компов коллег(ip 192.168.1.*) — рассылка приходит.

S>>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.


S>>В чём может быть проблема? Может быть, требуется дополнительная настройка OC?

S>>Код написан в MS VC2010 с Winsock2. ОС на тестируемой машине — Windows Server 2008 SP2.
MKM>Может быть это будет полезно (если используется впн):
MKM>http://support.microsoft.com/kb/981637
спасибо за ссылку, но VPN не используется.
Re[2]: Проблемы с UDP-multicast
От: yourSensey  
Дата: 25.07.11 09:45
Оценка:
Здравствуйте, MescalitoPeyot, Вы писали:

S>>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.


MP>А если попробовать заменить IP_ADD_SOURCE_MEMBERSHIP на IP_ADD_MEMBERSHIP?

Не совсем понимаю зачем(ведь присоединение к группе происходит и мультикаст-трафик начинает приходить на тестовую машину), но заменил

MP>Плюс еще можно попробовать заменить imr.imr_interface.s_addr с конкретного адреса на IP_ANY_ADDR (0.0.0.0)

там именно так и написано. Разве что присоединение к группе вынесено в отдельную функцию и что imr.imr_interface.s_addr = IP_ANY_ADDR становится не очень очевидным.
Re: Проблемы с UDP-multicast
От: MKM  
Дата: 25.07.11 10:25
Оценка:
Может быть Вам поможет IP_MULTICAST_TTL?

Можете ещё попробовать вот этот код.
Флаг flgSender определяет, будет ли программа сервером или клиентом.
Если у компьютера несколько сетевых интерфейсов, то клиент должен прослушивать туже сеть, в которую шлет данные сервер.

#pragma warning( push, 4 )

#pragma comment( lib, "Ws2_32.lib" )

#include <winsock2.h>
#include <conio.h>
#include <iostream>

int main() {

    const bool flgSender = true; // флаг Отправитель или Получатель



    WSADATA WSAData;
    int ErrCode = WSAStartup( MAKEWORD( 2, 2 ), &WSAData );    if ( 0 != ErrCode ) __debugbreak();



    // Перечисляем сетевые интерфейсы
    hostent *sh = gethostbyname( 0 );    if ( 0 == sh ) __debugbreak();
    if ( 0 == sh ) __debugbreak();

    int nAdapter = 0;
    for ( ; sh->h_addr_list[ nAdapter ] != 0; ++nAdapter );

    sockaddr_in adr;
    if ( nAdapter <= 0 ) 
        __debugbreak();
    else if ( nAdapter == 1 ) {
        memcpy( &adr.sin_addr, sh->h_addr_list[ 0 ], sh->h_length );
        std::cout << "Your IP is: " << inet_ntoa( adr.sin_addr ) << std::endl;
    }
    else {
        std::cout << "Select IP (press number from 1 to " << nAdapter << "):" << std::endl;
        for ( int i = 0; i < nAdapter; ++i ) {
            memcpy( &adr.sin_addr, sh->h_addr_list[ i ], sh->h_length );
            std::cout << ( i + 1 ) <<".    IP is: " << inet_ntoa( adr.sin_addr ) << std::endl;
        }
        std::cout << std::endl;

        int i;
        for (;;) {
            std::cin >> i;
            if ( ( i >= 1 ) && ( i <= nAdapter ) ) break;
            std::cout << "Press number from 1 to " << nAdapter << std::endl;
        };
        memcpy( &adr.sin_addr, sh->h_addr_list[ i-1 ], sh->h_length );
    }
    std::cout << std::endl;




    SOCKET s = WSASocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 0, WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF );
    if ( INVALID_SOCKET == s ) __debugbreak();


    const int reuse = 1;
    if ( 0 != setsockopt( s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>( &reuse ), sizeof( reuse ) ) ) __debugbreak();


    sockaddr_in local;
    memset( &local, 0, sizeof( local ) );
    local.sin_family = AF_INET;
    local.sin_addr = adr.sin_addr;
    local.sin_port = htons( flgSender ? 5678 : 5679 );

    if ( 0 != bind( s, (sockaddr*) &local, sizeof( local ) ) ) __debugbreak();


    sockaddr_in remote;
    memset( &remote, 0, sizeof( remote ) );
    remote.sin_family = AF_INET;
    remote.sin_addr.s_addr = inet_addr( "238.1.1.1" );
    remote.sin_port = htons( 5679 );


    SOCKET sR = WSAJoinLeaf( s, (sockaddr*) &remote, sizeof( remote ), 0, 0, 0, 0, flgSender ? JL_SENDER_ONLY : JL_RECEIVER_ONLY );
    if ( INVALID_SOCKET == sR ) __debugbreak();
    if ( s != sR ) __debugbreak();




    // Циклы приема / отправки
    int i;

    WSABUF Buffer;
    Buffer.len = sizeof( i );
    Buffer.buf = (CHAR*) &i;

    if ( flgSender ) {
        for ( i = 0; ! _kbhit(); i++ ) {
            DWORD NumberOfBytesSent = 0;
            if ( 0 != WSASendTo( s, &Buffer, 1, &NumberOfBytesSent, 0, (sockaddr*) &remote, sizeof( remote ), 0, 0 ) ) __debugbreak();
            std::cout << i << std::endl;
            Sleep( 1000 );
        }
    }
    else {
        for ( ; ! _kbhit(); ) {
            DWORD NumberOfBytesRecvd = 0, Flags = 0;
            if ( 0 != WSARecv( s, &Buffer, 1, &NumberOfBytesRecvd, &Flags, 0, 0 ) ) __debugbreak();
            std::cout << i << std::endl;
        }
    }




    if ( 0 != closesocket( s ) ) __debugbreak();

    if ( 0 != WSACleanup() ) __debugbreak();


    return 0;
}
Re[3]: Проблемы с UDP-multicast
От: MescalitoPeyot Украина  
Дата: 25.07.11 16:08
Оценка:
Здравствуйте, yourSensey, Вы писали:

S>Не совсем понимаю зачем(ведь присоединение к группе происходит и мультикаст-трафик начинает приходить на тестовую машину)


Не факт что IP_ADD_SOURCE_MEMBERSHIP всеми сторонами поддерживается (клиентом, сервером, роутером)

MP>>Плюс еще можно попробовать заменить imr.imr_interface.s_addr с конкретного адреса на IP_ANY_ADDR (0.0.0.0)

S>там именно так и написано.

Значит поменяй наоборот, на присоединение к группе на конкретном адресе Не помню подробностей, но вроде как на разных платформах есть глюки с этим параметром (где-то нужен ANY_ADDR, где-то конкретный адрес).
... << RSDN@Home 1.2.0 alpha 4 rev. 1138>>
Re: Проблемы с UDP-multicast
От: 5er Россия  
Дата: 26.07.11 09:00
Оценка:
Здравствуйте, yourSensey, Вы писали:

S>Только начал разбираться с работой udp-multicast. Под это есть задача написать небольшое приложение, подключающееся к multicast-группе и получающее с сервера данные.

S>Программа в целом написана. Она без проблем присоединяется к мулькаст-группе и сервер даже начинает слать данные(это видно в снифере Wireshark, мониторящем трафик на данной машине).

S>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.


S>В чём может быть проблема? Может быть, требуется дополнительная настройка OC?


S>Код написан в MS VC2010 с Winsock2. ОС на тестируемой машине — Windows Server 2008 SP2.


S>Собственно код клиента:



       join_source_group(RecvSocket, inet_addr(recvIpAddr), inet_addr(myIpAddr), INADDR_ANY);


Какое значение возвращает эта функция?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.