组播程序的例子
不知道为什么组播的等 级定义成三级,下面笔者只做自己加上一级便以讨论。
Level 3 只接收多播组的数据而不向多播组发放数据,其实这就是一个Level 2的例子
只不过只是接收数据而一了,就像网络会议旁听者一样J
下面只是列出两个例 子,读者可以根本这两个例子举一反三,编译环境要加上ws2_32.lib 还用到了以下的宏,可以放在文件的开始,或者放在单独的h文件。
#define ReportErr(str) \
{ \
printf("%s %d\n", __FILE__, __LINE__); \
printf(" %s %d\n", str, GetLastError()); \
}
#define WSAReportErr(str) \
{ \
printf("%s %d\n", __FILE__, __LINE__); \
printf(" %s %d\n", str, WSAGetLastError()); \
}
#define MC_ADDR "234.5.6.7"
#define MC_PORT 10000
#define MAXLEN 256
一个Level 1例子
只向多播组发送数据, 就像网络电视的Server端
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
void main(int argc, char **argv)
{
SOCKET s;
SOCKADDR_IN mcAddr;
int nMcLen;
int n;
char buf[MAXLEN];
WSADATA wsaData;
int nErr;
if(WSAStartup(0x0202, &wsaData) != 0)
{
ReportErr("WSAStartup(..)");
return;
};
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s == INVALID_SOCKET)
{
WSAReportErr("socket(...)");
WSACleanup();
return;
}
mcAddr.sin_family = AF_INET;
mcAddr.sin_addr.s_addr = inet_addr(MC_ADDR);
mcAddr.sin_port = htons(MC_PORT);
nMcLen = sizeof(mcAddr);
n = 0;
while(1)
{
Sleep(1000);
sprintf(buf, "This send to multicast group %s. seq: %d", MC_ADDR, n++);
nErr = sendto(s, buf, strlen(buf), 0, (struct sockaddr*)&mcAddr, nMcLen);
if(nErr == SOCKET_ERROR)
{
WSAReportErr("sendto(...)");
break;
}
printf("%s\n", buf);
}
WSACleanup();
}
一个Level 3例子
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
void main(int argc, char **argv)
{
SOCKET s;
SOCKADDR_IN mcAddr;
int nMcLen;
char buf[MAXLEN];
struct ip_mreq ipmr;
SOCKADDR_IN localAddr;
WSADATA wsaData;
int nErr;
if(WSAStartup(0x0202, &wsaData) != 0)
{
ReportErr("WSAStartup(..)");
return;
};
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s == INVALID_SOCKET)
{
WSAReportErr("socket(...)");
WSACleanup();
return;
}
/* */
memset(&localAddr, 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY)/*inet_addr(MC_ADDR)*/;
localAddr.sin_port = htons(MC_PORT);
nErr = bind(s, (struct sockaddr*)&localAddr, sizeof(localAddr));
if(nErr == SOCKET_ERROR)
{
WSAReportErr("bind(...)");
WSACleanup();
return;
}
/* Join multicast group */
ipmr.imr_multiaddr.s_addr = inet_addr(MC_ADDR);
ipmr.imr_interface.s_addr = htonl(INADDR_ANY);
nErr = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&ipmr, sizeof(ipmr));
if(nErr == SOCKET_ERROR)
{
WSAReportErr("setsockopt(.. IP_ADD_MEMBERSHIP ..)");
WSACleanup();
return;
}
mcAddr.sin_family = AF_INET;
mcAddr.sin_addr.s_addr = inet_addr(MC_ADDR);
mcAddr.sin_port = htons(MC_PORT);
nMcLen = sizeof(mcAddr);
while(1)
{
Sleep(1000);
nErr = recvfrom(s, buf, MAXLEN, 0, (struct sockaddr*)&mcAddr, &nMcLen);
if(nErr == SOCKET_ERROR)
{
continue;
}
printf("%s\n", buf);
}
WSACleanup();
}
参考书目
l Multicast over TCP/IP HOWTO
Juan-manriano de Geyeneche jmseyas@dit.upm.es
l ftp://ftp-eng.cisco.com/ipmulticast/
Cisco Co.
l TCP/IP详解 卷1 卷2
W. Richard Stevens , 译者: 范建华等
l Windows网络编程(第2版)
Anthony Jones, Jim Ohlund, 译者: 杨合庆