一、 广播
利用广播可以将数据发送到本地子网上的每个机器。广播的缺点是如果多个进程都发送广播数据,网络就会阻塞。为了进行广播,必须打开广播选项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; } } }