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