最近在研究一个局域网监控的系统,该系统中使用到了组播技术,这个也是我对组播技术的第一次接触,所以就写下了如下的初级认识吧!
组播(多播)
在使用组播技术时首先要知道的便是在计算机网络中为组播预留的IP地址:
组播IP地址
组播的VC实现
话不多说直接上代码(注:此代码也是从网上学习查找,自己加了些注释):接受数据端:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define MCASTADDR "233.0.0.1" //本例使用的多播组地址。
#define MCASTPORT 5150 //绑定的本地端口号。
#define BUFSIZE 1024 //接收数据缓冲大小。
int main( int argc,char ** argv)
{
WSADATA wsd;
struct sockaddr_in local,remote,from;
SOCKET sock,sockM;
TCHAR recvbuf[BUFSIZE];
/*struct ip_mreq mcast; // Winsock1.0 */
int len = sizeof( struct sockaddr_in);
int ret;
//初始化WinSock2.2
if( WSAStartup( MAKEWORD(2,2),&wsd) != 0 )
{
printf("WSAStartup() failed\n");
return -1;
}
/*
创建一个SOCK_DGRAM类型的SOCKET
其中,WSA_FLAG_MULTIPOINT_C_LEAF表示IP多播在控制面层上属于"无根"类型;
WSA_FLAG_MULTIPOINT_D_LEAF表示IP多播在数据面层上属于"无根",有关控制面层和 数据面层有关概念请参阅MSDN说明。
*/
if((sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("socket failed with:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
//将sock绑定到本机某端口上。
local.sin_family = AF_INET;
local.sin_port = htons(MCASTPORT);
local.sin_addr.s_addr = INADDR_ANY;
if( bind(sock,(struct sockaddr*)&local,sizeof(local)) == SOCKET_ERROR )
{
printf( "bind failed with:%d \n",WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
}
//加入多播组
remote.sin_family = AF_INET;
remote.sin_port = htons(MCASTPORT);
remote.sin_addr.s_addr = inet_addr( MCASTADDR );
/* Winsock2.0*/
if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),NULL,NULL,NULL,NULL,JL_BOTH)) == INVALID_SOCKET)
{
printf("WSAJoinLeaf() failed:%d\n",WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
}
//接收多播数据,当接收到的数据为"QUIT"时退出。
while(1)
{
if(( ret = recvfrom(sock,recvbuf,BUFSIZE,0,(struct sockaddr*)&from,&len)) == SOCKET_ERROR)
{
printf("recvfrom failed with:%d\n",WSAGetLastError());
closesocket(sockM);
closesocket(sock);
WSACleanup();
return -1;
}
if( strcmp(recvbuf,"QUIT") == 0 ) break;
else
{
recvbuf[ret] = '\0';
printf("RECV:' %s ' FROM <%s> \n",recvbuf,inet_ntoa(from.sin_addr)); }
}
closesocket(sockM);
closesocket(sock);
WSACleanup();
return 0;
}
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define MCASTADDR "233.0.0.1" //本例使用的多播组地址。
#define MCASTPORT 5150 //本地端口号。
#define BUFSIZE 1024 //发送数据缓冲大小。
int main( int argc,char ** argv)
{
WSADATA wsd;
struct sockaddr_in remote;//用于存储多播组的地址和端口信息
SOCKET sock;//本地通信套接字
SOCKET sockM;//组播通信套接字
TCHAR sendbuf[BUFSIZE];
int len = sizeof( struct sockaddr_in);
//初始化WinSock2.2
if( WSAStartup( MAKEWORD(2,2),&wsd) != 0 )
{
printf("WSAStartup() failed\n");
return -1;
}
//创建本地socket
if((sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("socket failed with:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
//加入多播组
/设置多播组信息
remote.sin_family = AF_INET;
remote.sin_port = htons(MCASTPORT);
remote.sin_addr.s_addr = inet_addr( MCASTADDR );
//将本地socket假如多播组
if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),NULL,NULL,NULL,NULL,JL_BOTH)) == INVALID_SOCKET)
{
printf("WSAJoinLeaf() failed:%d\n",WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
}
///
//发送多播数据,当用户在控制台输入"QUIT"时退出。
while(1)
{
printf("SEND : ");
scanf("%s",sendbuf);
//发送组播数据
//此处发送数据的socket也可以改为sock,发送socket只要是加入该组的socket就可以通过该组地址向改组内部主机发送数据
if( sendto(sockM,(char*)sendbuf,strlen(sendbuf),0,(struct sockaddr*)&remote,sizeof(remote))==SOCKET_ERROR)
{
printf("sendto failed with: %d\n",WSAGetLastError());
closesocket(sockM);
closesocket(sock);
WSACleanup();
return -1;
}
if(strcmp(sendbuf,"QUIT")==0) break;
Sleep(500);
}
closesocket(sockM);
closesocket(sock);
WSACleanup();
return 0;
}
最后说一句,其实对于组播的标识和单播是一样的都是通过唯一的一个IP地址和PORT号来唯一标识的。只是多播可以有组这个概念,在组中可以容纳很多个主机。