Только начал разбираться с работой 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;
}
Здравствуйте, yourSensey, Вы писали:
S>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.
А если попробовать заменить IP_ADD_SOURCE_MEMBERSHIP на IP_ADD_MEMBERSHIP? Плюс еще можно попробовать заменить imr.imr_interface.s_addr с конкретного адреса на IP_ANY_ADDR (0.0.0.0)
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
Здравствуйте, 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 не используется.
Здравствуйте, 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 становится не очень очевидным.
Можете ещё попробовать вот этот код.
Флаг 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;
}
Здравствуйте, yourSensey, Вы писали:
S>Не совсем понимаю зачем(ведь присоединение к группе происходит и мультикаст-трафик начинает приходить на тестовую машину)
Не факт что IP_ADD_SOURCE_MEMBERSHIP всеми сторонами поддерживается (клиентом, сервером, роутером)
MP>>Плюс еще можно попробовать заменить imr.imr_interface.s_addr с конкретного адреса на IP_ANY_ADDR (0.0.0.0) S>там именно так и написано.
Значит поменяй наоборот, на присоединение к группе на конкретном адресе Не помню подробностей, но вроде как на разных платформах есть глюки с этим параметром (где-то нужен ANY_ADDR, где-то конкретный адрес).
Здравствуйте, yourSensey, Вы писали:
S>Только начал разбираться с работой udp-multicast. Под это есть задача написать небольшое приложение, подключающееся к multicast-группе и получающее с сервера данные. S>Программа в целом написана. Она без проблем присоединяется к мулькаст-группе и сервер даже начинает слать данные(это видно в снифере Wireshark, мониторящем трафик на данной машине).
S>Проблема в том, что программа данных с боевого сервера не видит. Т.е. recvfrom() не отрабатывает. Однако, клиент исправно получает все пакеты от простейшего multicast-сервера, написанного мной и запущенного на той же машине, что и клиент. В Wireshark разницу в пакетах с локального тестового сервера и с удалённого боевого не заметил.
S>В чём может быть проблема? Может быть, требуется дополнительная настройка OC?
S>Код написан в MS VC2010 с Winsock2. ОС на тестируемой машине — Windows Server 2008 SP2.
S>Собственно код клиента: