组播定义:组播技术是IP网络数据传输三种方式之一,在介绍Ip组播技术之前,先对IP网络数据传输的单播、组播和广播方式做一个简单的介绍。
单播:
在发送者和每一接收者之间实现点对点网络 连接。如果一台发送者的接收者同时给多个的接收者传输相同的数据,也必须相应的复制多份的相同数据包。如果有大量主机希望获得数据包的同一份拷贝时,将导致发送者负担沉重、延迟长、网络阻塞、为保证一定的服务质量需要增加硬件和带宽。
广播:
广播指在IP子网内广播数据包,所有子子网内部的主机将收到这些数据包。广播意味着网络向子网每一个主机都投递一份数据包,不论这些主机是否乐于接收该数据包。所以广播的使用范围非常小, 只在本地子网内有效,通过路由器和网络设备控制广播传输。
组播:
组播在发送者和每一个接收者之间实现点对点网络连接。如果 一台发送者同时给多个接收者传输相同的数据,也只需复制一份相同的数据包。它提高了数据传送效率,减少了骨干网络出现拥塞的可能性。
服务端代码:
#include "stdafx.h"
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
//#define MCAST_POPT 8888
#define MCAST_PORT 4098
#define MCAST_ADDR "224.0.1.88"
#define LOCAL_ADDR "127.0.0.1"
#pragma pack(1)
//...
#pragma pop()
int _tmain(int argc, _TCHAR* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
printf("error\n");
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 ) {
WSACleanup( );
printf("error\n");
return -1;
}
char Name[255];//定义用于存放获得的主机名的变量
char *IP;//定义IP地址变量
//CString strIP="";
PHOSTENT hostinfo;
if(gethostname (Name, sizeof(Name)) == 0)
{
//如果成功地将本地主机名存放入由name参数指定的缓冲区中
if((hostinfo = gethostbyname(Name)) != NULL)
{
//这是获取主机名,如果获得主机名成功的话,将返回一个指针,指向hostinfo,hostinfo
//为PHOSTENT型的变量,下面即将用到这个结构体
IP = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
while(*hostinfo->h_addr_list !=NULL)
{
printf("IP::%s\n",inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list++));
}
//trIP.Format(IP);
}
}
printf("IP:%s\n",IP);
//IP ="127.0.0.1";
SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(MCAST_PORT);
//addrSrv.sin_addr.S_un.S_addr= inet_addr(LOCAL_ADDR);
addrSrv.sin_addr.S_un.S_addr= inet_addr(IP);//INADDR_ANY
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
bool loop = 1;
err = setsockopt(sockSrv,IPPROTO_IP,IP_MULTICAST_LOOP,reinterpret_cast<char FAR*>(&loop),sizeof(loop));
struct ip_mreq mreq;
mreq.imr_multiaddr.S_un.S_addr = inet_addr(MCAST_ADDR);
mreq.imr_interface.s_addr = inet_addr(IP);
err = setsockopt(sockSrv,IPPROTO_IP,IP_ADD_MEMBERSHIP,reinterpret_cast<char FAR*>(&mreq),sizeof(mreq));
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
char recvBuf[100];
int recvLen = 0;
int nCount = 10000;
//CommData m_data;
while(nCount--){
memset(recvBuf,0,sizeof(recvBuf));
if( (recvLen = recvfrom(sockSrv,recvBuf,dateSize,0,(SOCKADDR*)&addrClient,&len))!=-1){
printf("接收端口:%d ->%s已经连接上\r\n",addrClient.sin_port,inet_ntoa(addrClient.sin_addr));
memcpy(&m_data,recvBuf,recvLen);
}else
{
printf("wait....%d\n",10000 - nCount);
}
Sleep(10);
}
err = setsockopt(sockSrv,IPPROTO_IP,IP_DROP_MEMBERSHIP,reinterpret_cast<char FAR*>(&mreq),sizeof(mreq));
closesocket(sockSrv);
WSACleanup();
getchar();
return 0;
}
客户端代码:
#include<Winsock2.h>
#pragma comment(lib,"ws2_32")
#define MCAST_PORT 8888
#define MCAST_ADDR "224.0.1.88" //组播地址
int _tmain(int argc, _TCHAR* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 ) {
WSACleanup( );
return -1;
}
SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
bool opt = 1;
setsockopt(sockClient,SOL_SOCKET,SO_BROADCAST,reinterpret_cast<char FAR*>(&opt),sizeof(opt));
addrSrv.sin_family=AF_INET;
addrSrv.sin_addr.S_un.S_addr=inet_addr(MCAST_ADDR);
addrSrv.sin_port=htons(MCAST_PORT);
int n=20;
while(n--){
sendto(sockClient,"11000",strlen("11111"),0,
(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
}
closesocket(sockClient);
WSACleanup();
getchar();
return 0;
}