Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4042433
  • 博文数量: 366
  • 博客积分: 9916
  • 博客等级: 中将
  • 技术积分: 7195
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-29 23:27
个人简介

简单!

文章分类

全部博文(366)

文章存档

2013年(51)

2012年(269)

2011年(46)

分类: C/C++

2012-03-31 22:25:51

1       实验目的

掌握多播的原理及如何进行多播报文的发送和接受

2       注意事项

需包括 ws2tcpip.h 文件

发送者和所有接受者在同一网内

不考虑 TTL 值,回环状态

通过 setsockopt( ) 函数设置选项来实现多播数据的发送和接收

3       试验流程 3.1  多播数据发送端流程

l  创建一个数据报套接口

l  设置多播地址 ( 例: 239.192.1.2) 和端口号 ( 例: 12345)

l  调用 setsockopt( ) 函数设置发送的数据报本地接口 (IP_MULTICAST_IF)

struct in_addr interface_addr;

setsockopt ( socket, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr) );

l  使用 sendto 函数发送数据,目标地址为第二步所设置的多播地址

3.2  多播数据接收的流程

l  创建数据报套接口

l  绑定本地地址 (INADDR_ANY) 和端口号 ( 同发送端 )

l  调用 setsockopt( ) 函数设置 IP_ADD_MEMBERSHIP 选项,加入多播组

      struct ip_mreq {

             struct in_addr imr_multiaddr;   /* IP multicast address of group */

             struct in_addr imr_interface;    /* local IP address of interface */

               };

    struct ip_mreq mreq;

    setsockopt ( socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) );

l  接收数据

 

4       源代码 4.1  公共代码

#ifndef _MCASTLIB_H_

#define _MCASTLIB_H_

#include

#include

 

#ifdef __cplusplus

extern "C" {

#endif

int mc_join(SOCKET s, in_addr *mcaddr, in_addr *local_if);

int mc_setIF(SOCKET s, const DWORD local_out_if);

int mc_getIF(SOCKET s, DWORD *local_out_if);

int mc_setTTL(SOCKET s, const DWORD ttl);

int mc_getTTL(SOCKET s, DWORD *ttl);

int mc_setLoop(SOCKET s, const BOOL flag);

int mc_getLoop(SOCKET s, BOOL *flag);

int mc_leave(SOCKET s, in_addr *mcaddr, in_addr *local_if);

#ifdef __cplusplus

}

#endif

 

#endif // _MCASTLIB_H_

 

#include "MCastlib.h"

 

int mc_join(SOCKET s, in_addr *mcaddr, in_addr *local_if)

{

         ip_mreq mreq;

         memcpy(&(mreq.imr_interface), local_if, sizeof(in_addr)); // local if

         memcpy(&(mreq.imr_multiaddr), mcaddr, sizeof(in_addr)); // multicast group address

         return (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)));

}

 

// 为多播报文设置外出接口

int mc_setIF(SOCKET s, const DWORD local_out_if)

{

         return (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_out_if, sizeof(local_out_if)));

}

 

// 获取多播报文的外出接口

int mc_getIF(SOCKET s, DWORD *local_out_if)

{

         int len = sizeof(DWORD);

         return (getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_out_if, &len));

}

 

// 设置外出多播报文的 TTL 值,默认为 1

int mc_setTTL(SOCKET s, const DWORD ttl)

{

         return (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&ttl, sizeof(ttl)));

}

 

// 获取外出多播报文的 ttl

int mc_getTTL(SOCKET s, DWORD *ttl)

{

         int len = sizeof(DWORD);

         return (getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)ttl, &len));

}

 

// 启用或者禁止多播报文环回

int mc_setLoop(SOCKET s, const BOOL flag)

{

         return (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&flag, sizeof(flag)));

}

 

// 获取本地多播回环状态

int mc_getLoop(SOCKET s, BOOL *flag)

{

         int len = sizeof(BOOL);

         return (getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)flag, &len));

}

 

// 本地接口 local_if 离开多播组

int mc_leave(SOCKET s, in_addr *mcaddr, in_addr *local_if)

{

         ip_mreq mreq;

         memcpy(&(mreq.imr_interface), local_if, sizeof(in_addr)); // local if

         memcpy(&(mreq.imr_multiaddr), local_if, sizeof(in_addr)); // multicast group address

        

         return (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&mreq, sizeof(mreq)));

}

 

4.2  发送方

// 发送方

#pragma comment(lib, "ws2_32.lib")

#include

#include

#include "MCastlib.h"

 

void HandleError(char *func);

int main()

{

         WSAData wsaData;

         WSAStartup(WINSOCK_VERSION, &wsaData);

         /********* 创建一个数据报套接口 ****************/

         sockaddr_in local;

         memset(&local, 0, sizeof(local));

         local.sin_addr.s_addr = htonl(INADDR_ANY);

         local.sin_family = AF_INET;

         local.sin_port = htons(12345);

         SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);

         /*********************************************/

 

         /**** 调用 setsockopt( ) 函数设置发送的数据报本地接口 (IP_MULTICAST_IF)****/

         if (mc_setIF(sock, sizeof(sock)) == SOCKET_ERROR)

         {

                   printf("mc_setIF: %d\n", WSAGetLastError());

         }

         /**********************************************************************/

/*     // 获取默认的多播报文 TTL 值和回环状态

         DWORD ttl;

         if (mc_getTTL(sock, &ttl) == SOCKET_ERROR)

         {

                   printf("mc_getTTL: %d\n", WSAGetLastError());

         }

        

         BOOL loop;

         if (mc_getLoop(sock, &loop) == SOCKET_ERROR)

         {

                   printf("mc_getLoop: %d\n", WSAGetLastError());

         }

         printf("Multicast default: TTL=%d,LoopBack=%d\n", ttl, loop);

 

         // 设置 TTL 值为 219

         ttl = 219;

         if (mc_setTTL(sock, ttl) == SOCKET_ERROR)

         {

                   printf("mc_setTTL: %d\n", WSAGetLastError());

         }

*/    

 

         /*************** 设置多播地址和端口号 *************/

         sockaddr_in to;

         memset(&to, 0, sizeof(to));

         to.sin_addr.s_addr = inet_addr("239.192.1.2");

         to.sin_family = AF_INET;

         to.sin_port = htons(12345);

         /************************************************/

        

         /*** 使用 sendto 函数发送数据,目标地址为第二步所设置的多播地址 ****/

         char buf[60];

         while (true)

         {

                   printf("INPUT:\n");

                   gets(buf);

                   buf[strlen(buf)] = '\0';

                   int res = sendto(sock, buf, strlen(buf) + 1, 0, (sockaddr*)&to, sizeof(to));

                   if (res == SOCKET_ERROR)

                   {

                            HandleError("sendto");

                   }

                   else

                   {

                            printf("Send out %d bytes!\n", res);

                            if (strcmp(buf, "QUIT") == 0)

                            {

                                     break;

                            }

                   }

         }

         /***************************************************************/

         return 0;

}

 

void HandleError(char *func)

{

         int errCode = WSAGetLastError();

         char info[65] = {0};

         _snprintf(info, 64, "%s: %d\n", func, errCode);

         printf(info);

}

 

4.3  接收方

// 接收方

#pragma comment(lib, "ws2_32.lib")

#include

#include "MCastlib.h"

 

int main()

{

         // Init the winsock environment

         WSAData wsaData;

         if (WSAStartup(WINSOCK_VERSION, &wsaData) != 0)

         {

                   printf("Failed to Load a winsock.\n");

                   return 0;

         }

        

         // 创建数据报套接口

         SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);

         if (sock == INVALID_SOCKET)

         {

                   printf("socket: %d\n", WSAGetLastError());

                   return 0;

         }

         // 绑定本地地址 (INADDR_ANY) 和端口号 ( 同发送端 )

         sockaddr_in local;

         memset(&local, 0, sizeof(local));

         local.sin_family = AF_INET;

         local.sin_addr.s_addr = htonl(INADDR_ANY);

         local.sin_port = htons(12345);

 

         // bind local socket

         if (bind(sock, (sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)

         {

                   printf("bind: %d\n", WSAGetLastError());

                   return 0;

         }

        

         // 多播组地址

         in_addr mcaddr;

         mcaddr.S_un.S_addr = inet_addr("239.192.1.2");

         // 加入多播组

         if (mc_join(sock, &mcaddr, &(local.sin_addr)) == SOCKET_ERROR)

         {

                   printf("Join Multicast Group: %d\n", WSAGetLastError());

         }

        

         // 接收数据,考虑此时能收到发往哪些目的地址的 UDP 报文

         char buf[65];

         while (true)

         {

                   memset(buf, 0, 65);

                   if (recvfrom(sock, buf, 64, 0, NULL, NULL) == SOCKET_ERROR)

                   {

                            printf("recvfrom: %d\n", WSAGetLastError());

                            break;

                   }

                   else

                   {

                            printf("recvd: %s\n", buf);

                            if (strcmp(buf, "QUIT") == 0)

                            {

                                     break;

                            }

                   }

         }

         return 0;

}

摘自
阅读(8306) | 评论(0) | 转发(5) |
给主人留下些什么吧!~~