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

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

2017-09-19 13:53 816 查看
http://blog.csdn.net/dxzysk/article/details/55506450

源码下载地址: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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
[/code]
注意上面是只有一个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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[/code]

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
[/code]

运行结果

1.Server端



2.Client端



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