Только начал разбираться с работой 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;
}