组播技术的初级使用

7 篇文章 1 订阅

最近在研究一个局域网监控的系统,该系统中使用到了组播技术,这个也是我对组播技术的第一次接触,所以就写下了如下的初级认识吧!

组播(多播)

一种通讯模式。 主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接收到此组内的所有数据,网络中的 交换机路由器只向有需求者复制并转发其所需数据。 主机可以向 路由器请求加入或退出某个组,网络中的路由器和 交换机有选择的复制并传输数据,即只将组内数据传输给那些加入组的主机。这样既能一次将数据传输给多个有需要(加入组)的 主机,又能保证不影响其他不需要(未加入组)的主机的其他通讯。

在使用组播技术时首先要知道的便是在计算机网络中为组播预留的IP地址:

组播IP地址

组播IP地址用于标识一个IP组播组。IANA(internet assigned number authority)把D类地址空间分配给IP 组播,其范围是从224.0.0.0到239.255.255.255。
组播组可以是永久的也可以是临时的。 组播组地址中,有一部分由官方分配的,称为永久 组播组。永久 组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久 组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久 组播组使用的ip 组播,可以被临时 组播组利用。
224.0.0.0~224.0.0.255为预留的组播 地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用。
224.0.1.0~238.255.255.255为用户可用的 组播地址(临时组地址),全网范围内有效。
239.0.0.0~239.255.255.255为本地管理 组播地址,仅在特定的本地范围内有效。

组播的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号来唯一标识的。只是多播可以有组这个概念,在组中可以容纳很多个主机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值