多播报文的发送和接收

<!-- [if !supportLists]-->1 <!-- [endif]-->实验目的

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

<!-- [if !supportLists]-->2 <!-- [endif]-->注意事项

需包括 ws2tcpip.h 文件

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

不考虑 TTL 值,回环状态

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

<!-- [if !supportLists]-->3 <!-- [endif]-->试验流程

<!-- [if !supportLists]-->3.1 <!-- [endif]-->多播数据发送端流程

<!-- [if !supportLists]-->l <!-- [endif]-->创建一个数据报套接口

<!-- [if !supportLists]-->l <!-- [endif]-->设置多播地址 ( 例: 239.192.1.2) 和端口号 ( 例: 12345)

<!-- [if !supportLists]-->l <!-- [endif]-->调用 setsockopt( ) 函数设置发送的数据报本地接口 (IP_MULTICAST_IF)

struct in_addr interface_addr;

setsockopt ( socket, IPPROTO_IP, IP_MULTICAST_IF,

&interface_addr, sizeof(interface_addr) );

<!-- [if !supportLists]-->l <!-- [endif]-->使用 sendto 函数发送数据,目标地址为第二步所设置的多播地址

<!-- [if !supportLists]-->3.2 <!-- [endif]-->多播数据接收的流程

<!-- [if !supportLists]-->l <!-- [endif]-->创建数据报套接口

<!-- [if !supportLists]-->l <!-- [endif]-->绑定本地地址 (INADDR_ANY) 和端口号 ( 同发送端 )

<!-- [if !supportLists]-->l <!-- [endif]-->调用 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) );

<!-- [if !supportLists]-->l <!-- [endif]-->接收数据

<!-- [if !supportLists]-->4 <!-- [endif]-->源代码

<!-- [if !supportLists]-->4.1 <!-- [endif]-->公共代码

#ifndef _MCASTLIB_H_

#define _MCASTLIB_H_

#include <Winsock2.h>

#include <WS2tcpip.h>

#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)));

}

<!-- [if !supportLists]-->4.2 <!-- [endif]-->发送方

// 发送方

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

#include <stdio.h>

#include <WINSOCK2.H>

#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);

}

<!-- [if !supportLists]-->4.3 <!-- [endif]-->接收方

// 接收方

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

#include <stdio.h>

#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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值