您的位置:首页 > 理论基础 > 计算机网络

windows C++ 通过UDP广播获取网络中所有设备ip地址

2017-02-17 11:47 891 查看
说明:

源码下载地址:http://download.csdn.net/detail/dxzysk/9756896

源码使用说明,先在需要获取IP地址的主机上运行server端程序,然后在需要搜索主机的Pc上运行client端程序

本文是windows版,VC++,在VS2010环境下调试成功。有时候需要搜索网络中的设备,机器,服务器等,这就要要用到UDP广播的方式,发送广播命令,广播给网络中的每一个主机,该主机或设备接收到广播命令后,立刻发送给请求端自己的设备信息,这里以IP信息为例子。

思路

在每一个设备中部署sever端程序进行监控,client端发送广播命令,每一个server收到命令后,返回给client自己的ip地址信息,给出代码如下,其中,有部分,比如获取ip地址参考来自网络,尊重原创,乐于分享。

server端(windows控制台程序)

server端监听广播命令”GetIPAddr”,收到命令后就相应

#include <WinSock2.h>
#include <stdio.h>
#include <iostream>
using namespace std;

#pragma comment(lib, "ws2_32.lib")

#define GET_HOST_COMMAND "GetIPAddr"
const int MAX_BUF_LEN = 255;
#define SERVER_PORT 12811

//只返回一个ip地址
bool GetLocalIP(char* ip)
{
//1.初始化wsa
WSADATA wsaData;
int ret=WSAStartup(MAKEWORD(2,2),&wsaData);
if (ret!=0)
{
return false;
}
//2.获取主机名
char hostname[256];
ret=gethostname(hostname,sizeof(hostname));
if (ret==SOCKET_ERROR)
{
return false;
}
//3.获取主机ip
HOSTENT* host=gethostbyname(hostname);
if (host==NULL)
{
return false;
}
//4.转化为char*并拷贝返回
strcpy(ip,inet_ntoa(*(in_addr*)*host->h_addr_list));
return true;
}

bool doServer(){
int m_nPort = SERVER_PORT;

SOCKET sClient;
sockaddr_in clientAddr,bindAddr;
WSADATA wsdata;

//启动SOCKET库,版本为2.0
WORD    wVer=MAKEWORD(2,0);
if( 0 != WSAStartup(wVer,&wsdata) )
{
//AfxMessageBox(L"Not Support Socket2.0");
return false;
}

//用UDP初始化套接字
sClient=socket(AF_INET,SOCK_DGRAM,0);
//设置该套接字为广播类型,
BOOL optval=TRUE;
bindAddr.sin_family=AF_INET;
bindAddr.sin_addr.s_addr=htonl(INADDR_ANY);
bindAddr.sin_port=htons(m_nPort);
setsockopt(sClient,SOL_SOCKET,SO_BROADCAST,(char FAR *)&optval,sizeof(optval));
bind(sClient,(sockaddr *)&bindAddr,sizeof(sockaddr_in));

int nAddrLen = sizeof(SOCKADDR);
char buf[256] = {0};
int fromlength=sizeof(SOCKADDR);
printf("the server is start.\n");

char ipaddr[30] = {0};

char buff[MAX_BUF_LEN] = "";
if (GetLocalIP(ipaddr))
{
sprintf(buff, "my ip is:%s", ipaddr);
}
else
{
sprintf(buff, "%s", "my ip is:******");
}

//有多个ip地址的时候,这样调用
//IPInfo ips[10];
//int len1 = 0;
//GetLocalIPs(ips, 10,&len1);

while(true)
{
int nRet = recvfrom(sClient,buf,256,0,(struct sockaddr FAR *)&clientAddr,(int FAR *)&fromlength);
if( SOCKET_ERROR != nRet )
{
char    *pIPAddr = inet_ntoa(clientAddr.sin_addr);
if( NULL != pIPAddr )
{
WCHAR    wzIPBuffer[32] = {0};
printf("clientAddr: %s\n", pIPAddr);
printf("receive command: %s\n", buf);
}
if (strcmp(buf,GET_HOST_COMMAND) != 0)
{
printf("the command not valid and was ignored.\n", buf);
continue;
}
// 发送数据
int nSendSize = sendto(sClient, buff, strlen(buff), 0, (SOCKADDR*)&clientAddr, nAddrLen);
if(SOCKET_ERROR == nSendSize)
{
int err = WSAGetLastError();
printf("\"sendto\" error!, error code is %d\n", err);
return false;
}

}
else
{
//AfxMessageBox(L"Recv UDP Failed");
}

Sleep(1000);
}

closesocket(sClient);
return true;
}

int main()
{
if (!doServer())
{
printf("sever returned an error");
return -1;
}
return 0;
}


注意上面是只有一个Ip地址的情况,有的机器可能会有多个IP地址,不同的网络,有线网,无线wifi等,需要获取多个ip地址的方法:

//结构体记录ip信息
typedef struct tagIPInfo
{
char ip[30];
}IPInfo;

//获取多个ip地址信息列表
bool GetLocalIPs(IPInfo* ips,int maxCnt,int* cnt)
{
//1.初始化wsa
WSADATA wsaData;
int ret=WSAStartup(MAKEWORD(2,2),&wsaData);
if (ret!=0)
{
return false;
}
//2.获取主机名
char hostname[256];
ret=gethostname(hostname,sizeof(hostname));
if (ret==SOCKET_ERROR)
{
return false;
}
//3.获取主机ip
HOSTENT* host=gethostbyname(hostname);
if (host==NULL)
{
return false;
}
//4.逐个转化为char*并拷贝返回
*cnt=host->h_length<maxCnt?host->h_length:maxCnt;
for (int i=0;i<*cnt;i++)
{
in_addr* addr=(in_addr*)*host->h_addr_list;
strcpy(ips[i].ip,inet_ntoa(addr[i]));
}
return true;
}


client端(windows控制台程序)

client端发送”GetIPAddr”命令,并及时接收client端发过来的信息

//#include "stdafx.h"
#include <WinSock2.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

const int MAX_BUF_LEN = 255;

#define GET_HOST_COMMAND "GetIPAddr"
#define CLIENT_PORT 11121
#define SERVER_PORT 12811

int main()
{
int nPort = SERVER_PORT;
WORD wVersionRequested;
WSADATA wsaData;
int err;

// 启动socket api
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return -1;
}

if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup( );
return -1;
}

// 创建socket
SOCKET connect_socket;
connect_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(INVALID_SOCKET == connect_socket)
{
err = WSAGetLastError();
printf("\"socket\" error! error code is %d\n", err);
return -1;
}

// 用来绑定套接字
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(CLIENT_PORT);
sin.sin_addr.s_addr = 0;

// 用来从网络上的广播地址接收数据
SOCKADDR_IN sin_from;
sin_from.sin_family = AF_INET;
sin_from.sin_port = htons(nPort);
sin_from.sin_addr.s_addr = INADDR_BROADCAST;

//设置该套接字为广播类型,
bool bOpt = true;
setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char*)&bOpt, sizeof(bOpt));

// 绑定套接字
err = bind(connect_socket, (SOCKADDR*)&sin, sizeof(SOCKADDR));
if(SOCKET_ERROR == err)
{
err = WSAGetLastError();
printf("\"bind\" error! error code is %d\n", err);
return -1;
}

printf("the client is start.\n");
int nAddrLen = sizeof(SOCKADDR);
char buff[MAX_BUF_LEN] = "";
int nLoop = 0;

char    szMsg[]=GET_HOST_COMMAND;
int nLen=sizeof(sin_from);
if( SOCKET_ERROR==sendto(connect_socket, szMsg, strlen(szMsg), 0, (sockaddr*)&sin_from, nLen) )
{
// AfxMessageBox(L"Send UDP Failed");
return -1;
}

printf("send broadcast data:%s\n", GET_HOST_COMMAND);

while(true)
{
// 接收数据
int nSendSize = recvfrom(connect_socket, buff, MAX_BUF_LEN, 0, (SOCKADDR*)&sin_from, &nAddrLen);
if(SOCKET_ERROR == nSendSize)
{
err = WSAGetLastError();
printf("\"recvfrom\" error! error code is %d\n", err);
return -1;
}
buff[nSendSize] = '\0';
printf("received ip: %s\n", buff);
}

return 0;
}


运行结果

1.Server端



2.Client端



运行结果说明:两个ip地址一样,是因为client和server我都运行在同一台机器上,如果有多台server,则client可以搜素到多个ip,受到条件限制,这里只有一个。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  udp 广播 ip