SOCKET IP多播

SOCKET IP多播


以前的笔记,注释都在代码里,移过来了。

// IP多播.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <process.h>
#include <WinSock2.h>
#include <ws2ipdef.h>
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)

/*

1.选项IP_MULTICASE_TTL

选项IP_MULTICAST_TTL允许设置超时TTL,范围为0~255之间的任何值,例如:
unsigned char ttl=255;
setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));

2.选项IP_MULTICAST_IF

选项IP_MULTICAST_IF用于设置组播的默认默认网络接口,会从给定的网络接口发送,另一个网络接口会忽略此数据。例如:
struct in_addr addr;
setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr))

3. 选项IP_MULTICAST_LOOP
参数addr是希望多播输出接口的IP地址,使用INADDR_ANY地址回送到默认接口。

默认情况下,当本机发送组播数据到某个网络接口时,在IP层,数据会回送到本地的回环接口,选项IP_MULTICAST_LOOP用于控制数据是否回送到本地的回环接口。例如:
unsigned char loop;
setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop))

参数loop设置为0禁止回送,设置为1允许回送。
*/

BOOL SetTTL(SOCKET & s, int nTTL) {
	//TTL 权限执行如下约定:
	/*
	0 多播封包被限制在同一个主机
	1 多播封包被限制在同一个子网
	32 多播封包被限制在同一个站点
	64 多播封包被限制在同一个地区
	128 多播封包被限制在同一个大陆
	255 多播封包没有限制
	*/
	int nRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nTTL, sizeof(nTTL));
	return nRet != SOCKET_ERROR;
}


unsigned int WINAPI recvThread(PVOID lParam) {

	SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
	//ULONG ul = 0;
	//ioctlsocket(s, FIONBIO, (unsigned  long*)&ul);

	if (!SetTTL(s, 1)) {
		std::cout << "设置TTL失败\n" << std::endl;
		return -1;
	}

	bool bReuse = true;
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)bReuse, 1);

	SOCKADDR_IN sin;
	sin.sin_family = AF_INET;
	sin.sin_port = ntohs(8888);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;

	if (::bind(s, (SOCKADDR *)&sin, sizeof(sin)) == SOCKET_ERROR) {
		printf_s("绑定出错%d\n", GetLastError());
		closesocket(s);
		return 1;
	}

	/*
	//这是不限制来源IP
	//设置ip_mreq 结构
	ip_mreq mreq;
	mreq.imr_interface.S_un.S_addr = inet_addr("192.168.0.5"); //本地ip
	mreq.imr_multiaddr.S_un.S_addr = inet_addr("234.5.6.7"); //多播组ip
	setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));
	*/


	//限制来源IP
	//设置ip_mreq_source 结构
	struct ip_mreq_source mreqsrc;
	mreqsrc.imr_interface.S_un.S_addr = inet_addr("192.168.0.5"); //本地ip
	mreqsrc.imr_multiaddr.S_un.S_addr = inet_addr("234.5.6.7"); //多播组ip
	mreqsrc.imr_sourceaddr.S_un.S_addr = inet_addr("192.168.0.5");//指定的源IP 每规定一次 都要 IP_ADD_SOURCE_MEMBERSHIP
	//如果要移除 可以使用 IP_DROP_SOURCE_MEMBERSHIP

	if(setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char*)&mreqsrc, sizeof(mreqsrc)) == SOCKET_ERROR)
		std::cout << "设置失败" << std::endl;

	//又添加了一个指定的源IP
	mreqsrc.imr_sourceaddr.S_un.S_addr = inet_addr("192.168.0.7");
	setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char*)&mreqsrc, sizeof(mreqsrc));
	


	SOCKADDR_IN addrRemote;
	int nLen = sizeof(addrRemote);
	char sz[256] = { 0 };
	while (true) {
		int nRet = recvfrom(s, sz, 256, 0, (sockaddr*)&addrRemote, &nLen);
		if (nRet > 0)
			printf_s("来自ip:%s:%d,内容:%s \n", inet_ntoa(addrRemote.sin_addr), htons(addrRemote.sin_port), sz);
	}

}





int main()
{
	WSAData wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = ntohs(8888);
	sin.sin_addr.S_un.S_addr = inet_addr("234.5.6.7");


	//先创建接收线程,下面是个死循环
	UINT dwThreadId;
	HANDLE hRecvthread = (HANDLE)_beginthreadex(NULL, 0, recvThread, NULL, 0, &dwThreadId);
	CloseHandle(hRecvthread);


	char sz[] = "测试内容。。。。\r\n";
	while (true) {
		int n = sendto(s, sz, strlen(sz), 0,(sockaddr *)&sin, sizeof(sin));
		Sleep(3000);
	}

	WSACleanup();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没事干写博客玩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值