广播和组播

套接字除了单播通信(点对点外),还有广播和组播通信两种工作方式。

一、   广播

利用广播可以将数据发送到本地子网上的每个机器。广播的缺点是如果多个进程都发送广播数据,网络就会阻塞。为了进行广播,必须打开广播选项SO_BROADCAST,然后用recvfrom,sendto等函数收发广播数据。

对于UDP来说,存在一个特定的广播地址—255.255.255.255,广播数据都应该发送到这里。理论上讲,可以在整个Internet发送广播数据,但是几乎没有路由器转发广播数据,所以,广播程序只能应用在本地子网中。

发送端代码如下:

#include "stdafx.h"
#include "stdio.h"
#include <windows.h>
#pragma comment(lib, "WS2_32")
int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if(WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}

	SOCKET s=socket(AF_INET,SOCK_DGRAM,0);//创建UDP
	//有效的SO_BROADCAST 选项
	BOOL bBroadcast=TRUE;
	setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char*)&bBroadcast,sizeof(BOOL));
	//设置广播地址
	SOCKADDR_IN bcast;
	bcast.sin_family=AF_INET;
	bcast.sin_addr.s_addr=INADDR_BROADCAST;//inet_addr("255.255.255.255");
	bcast.sin_port=htons(4567);
	//发送广播
	printf("开始向4567端口发送数据……\n\n");
	char sz[]="This is just a test.\r\n";
	while(TRUE)
	{
		sendto(s,sz,strlen(sz),0,(sockaddr*)&bcast,sizeof(bcast));
		Sleep(5000);
	}

	WSACleanup();	
	return 0;
}

接收端代码如下:

#include "stdafx.h"
#include "stdio.h"
#include <windows.h>
#pragma comment(lib, "WS2_32")
int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if(WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}

	SOCKET s=socket(AF_INET,SOCK_DGRAM,0);//创建UDP	
	
	SOCKADDR_IN bcast;
	bcast.sin_family=AF_INET;
	bcast.sin_addr.s_addr=INADDR_ANY;
	bcast.sin_port=ntohs(4567);
	
	if(bind(s,(sockaddr*)&bcast,sizeof(bcast))==SOCKET_ERROR)
	{
		printf("bind() failed\n");
		return 0;
	}

	//接收广播
	printf("开始在4567端口接收广播数据……\n\n");
	SOCKADDR_IN addrRemote;
	int nLen=sizeof(addrRemote);
	char sz[256];
	while(TRUE)
	{
		int nRet=recvfrom(s,sz,256,0,(sockaddr*)&addrRemote,&nLen);
		if(nRet>0)
		{
			sz[nRet]='\0';
			printf(sz);
		}
	}

	WSACleanup();	
	return 0;
}

二、组播通信

    在internet中多点传输一般使用组播通信。

#include "stdafx.h"
#include "stdio.h"

#include "MultiSock.h"
int _tmain(int argc, _TCHAR* argv[])
{
	CMultiSock mySock;
	mySock.RecvPacket();	
	return 0;
}

#pragma once
#include <Ws2tcpip.h>
#include <windows.h>
#pragma comment(lib, "WS2_32")
class CMultiSock
{
public:
	CMultiSock(void);
	~CMultiSock(void);
	DWORD m_dwMultiAddr;	// 此组使用的多播地址
	USHORT m_port;
	SOCKET s;               //套接字
	sockaddr_in si;
	void RecvPacket(void);
};

#include "StdAfx.h"
#include "MultiSock.h"

CMultiSock::CMultiSock(void)
{
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if(WSAStartup(sockVersion, &wsaData) != 0)
	{
		return;
	}
	s = socket(AF_INET, SOCK_DGRAM, 0);

	// 允许其它进程使用绑定的地址
	BOOL bReuse = TRUE;
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(BOOL));
	m_dwMultiAddr=inet_addr("234.5.6.7");//组播的IP地址;
	m_port=4567;

	// 绑定到4567端口	
	si.sin_family = AF_INET;
	si.sin_port = ntohs(m_port);
	si.sin_addr.S_un.S_addr = INADDR_ANY;
	bind(s, (sockaddr*)&si, sizeof(si));	

	
	//设置多播TTL值
	int nTTL=64;	
	int nRet=setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&nTTL,sizeof(nTTL));
	if(nRet==SOCKET_ERROR)
	{
		return;
	}
	
	/*
	//设置要使用的发送接口
	in_addr addr;//=INADDR_ANY;
	nRet=setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,(char*)&addr,sizeof(addr));
	if(nRet==SOCKET_ERROR)
	{
		return;
	}
	*/

	// 加入多播组
	ip_mreq	mcast;
	mcast.imr_interface.S_un.S_addr = INADDR_ANY;
	mcast.imr_multiaddr.S_un.S_addr = m_dwMultiAddr;  // 多播地址为234.5.6.7
	setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast));	
	
	//发送加入组消息
	sockaddr_in sRemote;
	sRemote.sin_family=AF_INET;
	sRemote.sin_port=htons(m_port);
	sRemote.sin_addr.S_un.S_addr=m_dwMultiAddr;	
	int ret=sendto(s,"Join this party\r\n",strlen("Join this party\r\n"),0,(sockaddr*)&sRemote,sizeof(sRemote));
	
}

CMultiSock::~CMultiSock(void)
{
	
	//发送加入组消息
	sockaddr_in sRemote;
	sRemote.sin_family=AF_INET;
	sRemote.sin_port=htons(m_port);
	sRemote.sin_addr.S_un.S_addr=m_dwMultiAddr;	
	sendto(s,"Leave this party\r\n",strlen("Leave this party\r\n"),0,(sockaddr*)&sRemote,sizeof(sRemote));

	ip_mreq mcast;
	mcast.imr_interface.S_un.S_addr=INADDR_ANY;//加入组的IP地址
	mcast.imr_multiaddr.S_un.S_addr=m_dwMultiAddr;
	setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char*)&mcast,sizeof(mcast));
	
	WSACleanup();	
}

void CMultiSock::RecvPacket(void)
{	
	
	// 接收多播组数据
	printf(" 开始接收多播组234.5.6.7上的数据... \n");
	char buf[1280];
	int nAddrLen = sizeof(si);
	while(TRUE)
	{
		int nRet = ::recvfrom(s, buf, strlen(buf), 0, (sockaddr*)&si, &nAddrLen);
		if(nRet != SOCKET_ERROR)
		{
			buf[nRet] = '\0';
			printf(buf);
		}
		else
		{
			int n = ::WSAGetLastError();
			break;
		}
	}
	
		
}





你可能感兴趣的:(JOIN,工作,socket,Class,internet,路由器)