首页 > 其他分享 >多播报文的发送和接收

多播报文的发送和接收

时间:2023-01-04 14:32:20浏览次数:37  
标签:播报 addr mc int IP 发送 接收 local SOCKET


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

 

4.2  发送方

//  发送方
#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)****/
mc_setIF(sock, sizeof(sock))
{
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 <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;
}

标签:播报,addr,mc,int,IP,发送,接收,local,SOCKET
From: https://blog.51cto.com/u_15929756/5988628

相关文章