1 // getNativeComputerNetInformation.cpp
2 /*
3 在网络编程中,服务器端需要知道本机的IP;唯一标识一台机器的MAC地址;
4
5 功能的实现都非常简单,有五种函数可以直接调用:
6 1.用于获取本地网络适配器信息的函数:
7 DWORD GetAdaptersInfo( PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen );
8 2.用于获取本地主机名、域名和DNS服务器信息的函数:
9 DWORD GetNetworkParamsInfo(PFIXED_INFO pFixedInfo, PULONG pOutBufLen );
10 3.用于获取本地计算机网络接口数量的函数
11 DWORD GetNumberOfInterfaces(PDWORD pdwNumIf);
12 4.用于获取本地主机名、域名和DNS服务器信息的函数
13 DWORD GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen );
14 5.获取本地计算机IP地址表的函数
15 DWORD GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder );
16 */
17 #include <stdio.h>
18 #include <WinSock2.h>
19 #include <iphlpapi.h>
20
21 #pragma comment(lib, "IPHLPAPI.lib")
22 #pragma comment(lib, "ws2_32.lib")
23
24 void main()
25 {
26 // 各类函数声明
27 int GetAdaptersInfoFunction(); // 获取本地网络适配器信息的函数
28 int GetNetworkParamsFunction(); // 获取本地主机名、域名和DNS服务器信息
29 int GetInterfacesFunction(); // 获取本地计算机网络接口的基本信息
30 int GetIpAddrTableFunction(); // 获取本地计算机的IP地址
31
32 // 各类函数调用
33 char choice;
34 do{
35 system("cls");
36 printf("1.获取本地网络适配器信息的函数 GetAdaptersInfoFunction();\n");
37 printf("2.获取本地主机名、域名和DNS服务器信息 GetNetworkParamsFunction();\n");
38 printf("3.获取本地计算机网络接口的基本信息 GetInterfacesFunction();\n");
39 printf("4.获取本地计算机的IP地址 GetIpAddrTableFunction();\n");
40 printf("0.退出程序\n");
41 printf("请输入需要调用的函数:");
42 scanf("%c", &choice);
43 printf("\n\n");
44 switch(choice){
45 case '0': break;
46 case '1': GetAdaptersInfoFunction(); break;
47 case '2': GetNetworkParamsFunction(); break;
48 case '3': GetInterfacesFunction(); break;
49 case '4': GetIpAddrTableFunction(); break;
50 default: break;
51 }
52 }while('0' != choice);
53 }
54
55
56 /**
57 * 用于获取本地网络适配器信息的函数:
58 * DWORD GetAdaptersInfo(
59 * _in PIP_ADAPTER_INFO pAdapterInfo; // 结构体保存获取到的网络适配器的信息
60 * _out PULONG pOutBufLen // 保存pAdapterInfo缓冲区的大小
61 * );
62 *
63 * 网络适配器的信息的结构体:网卡信息有:网卡名,网卡描述,MAC地址,网卡IP,网卡默认网关等
64 * typedef struct _IP_ADAPTER_INFO {
65 * struct _IP_ADAPTER_INFO* Next; // 指定网络适配器链表中的下一个网络适配器;由于一台电脑可能有多个网卡,所以是链表结构
66 * DWORD ComboIndex; // 预留变量
67 * char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; // 网络适配器的名称
68 * char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; // 网络适配器的描述信息
69 * UINT AddressLength; // 网络适配器MAC的长度
70 * BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; // 网络适配器的MAC地址
71 * DWORD Index; // 网络适配器索引(重启计算机会改变的值)
72 * UINT Type; // 网络适配器的类型
73 * UINT DhcpEnabled; // 指定该网络适配器上是否启用了DHCP
74 * PIP_ADDR_STRING CurrentIpAddress; // 预留变量
75 * IP_ADDR_STRING IpAddressList; // 与此网络适配器上相关联的IP地址列表
76 * IP_ADDR_STRING GatewayList; // 该网络适配器上定义的IP地址的默认网关
77 * IP_ADDR_STRING DhcpServer; // 该网络适配器上定义的DHCP服务器的IP地址
78 * BOOL HaveWins; // 标明该网络适配器是否启用了WINS
79 * IP_ADDR_STRING PrimaryWinsServer; // 主WIN服务器的IP地址
80 * IP_ADDR_STRING SecondaryWinsServer; // 从WINS服务器的IP地址
81 * time_t LeaseObtained; // 当前的DHCP租借获取的时间,只有在启用DHCP时生效
82 * time_t LeaseExpires; // 当前的DHCP租借失败的时间,只有在启用DHCP时生效
83 * } IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
84
85
86 typedef struct _IP_ADDR_STRING { //存储一个IP地址和其相应的子网掩码,同时作为点分十进制的字符串
87 struct _IP_ADDR_STRING* Next; //由于一个网卡可能有多个IP,故为链表结构
88 IP_ADDRESS_STRING IpAddress;
89 IP_MASK_STRING IpMask;
90 DWORD Context;
91 } IP_ADDR_STRING, *PIP_ADDR_STRING;
92
93 typedef struct { //存储一个IP地址,同时作为点分十进制的字符串
94 char String[4 * 4];
95 } IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
96
97 **/
98 //一台机器上可能不止有一个网卡,但每一个网卡只有一个MAC地址,而每一个网卡可能配置多个IP地址;如平常的笔记本电脑中,就会有无线网卡和有线网卡两种;因此,如果要获得本机所有网卡的IP和MAC地址信息,则必须顺序获得每个网卡,再依次获取其信息;
99 int GetAdaptersInfoFunction() // 获取本地网络适配器信息的函数
100 {
101 // 变量声明
102 IP_ADAPTER_INFO *pAdapterInfo; // 指定获取到的网络信息结构体链表的指针
103 ULONG ulOutBufLen; // 获取到网络信息结构体链表的长度
104 DWORD dwRetVal; // 返回调用编码
105
106 // 获取本地网络适配器的信息
107 // 为pAdapterINfo分配空间
108 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
109 ulOutBufLen = sizeof(IP_ADAPTER_INFO);
110 // 需要两次调用GetAdaptersInfo()函数
111 // 第1次调用GetAdaptersInfo(), 获取返回结果的大小保存到ulOutBufLen中
112 // 因为网络信息结构体链表的默认长度是不知道的
113 if(ERROR_SUCCESS != GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) ){
114 free(pAdapterInfo);
115 pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
116 }
117 // 第2次调用GetAdaptersInfo(), 获取本地网络信息保存到结构体pAdapterInfo中
118 if(ERROR_SUCCESS != (dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen))){
119 printf("GetAdaptersInfo Error! &d\n", dwRetVal);
120 exit(1);
121 }
122
123 // 显示本地网络适配器信息,从pAdapterInfo获取并显示本地网络信息
124 PIP_ADAPTER_INFO pAdapter;
125 pAdapter = pAdapterInfo;
126 while(pAdapter){
127 printf("网络适配器名: \t\t%s\n", pAdapter->AdapterName);
128 printf("网络适配器描述: \t%s\n\n", pAdapter->Description);
129 printf("MAC地址:\t\t");
130 // 处理MAC地址
131 for(unsigned int i = 0; i < pAdapter->AddressLength; ++i){
132 if(i == (pAdapter->AddressLength -1 ) ){ // 最后一次输入换行
133 printf("%.2x\n", (int)pAdapter->Address[i]);
134 }
135 else{
136 printf("%.2X-", (int)pAdapter->Address[i]);//x十六进制(x:会是a,b,c,d,e;X:会是A,B,C,D,E)
137 }
138 }
139 printf("IP地址: \t\t%s\n", pAdapter->IpAddressList.IpAddress.String);
140 printf("子网掩码: \t\t%s\n", pAdapter->IpAddressList.IpMask.String);
141 printf("网关: \t\t\t%s\n", pAdapter->GatewayList.IpAddress.String);
142 printf("---------------\n");
143 if(pAdapter -> DhcpEnabled){ // 指定该网络适配器上是否启用了DHCP(动态主机配置协议)
144 printf("启用DHCP: \t\t是\n");
145 printf("DHCP服务器: \t\t%s\n", pAdapter->DhcpServer.IpAddress.String);
146 }
147 else{
148 printf("启用DHCP: \t\t否\n");
149 }
150 // 处理下一个网络适配器
151 pAdapter = pAdapter -> Next;
152 if(pAdapter){
153 printf("\n\n**************************************************************\n");
154 }
155 }
156
157 // 释放资源
158 if(pAdapterInfo){
159 free(pAdapterInfo);
160 }
161
162 printf("\n\n");
163 system("pause");
164 return 0;
165 }
166
167 /**
168 * 用于获取本地主机名、域名和DNS服务器信息的函数:
169 * DWORD GetNetworkParamsInfo(
170 * _out PFIXED_INFO pFixedInfo; // 使用FIXED_INFO结构体保存获取到的本地网络参数的信息
171 * _in PULONG pOutBufLen // 保存pFixedInfo缓冲区的大小
172 * );
173 *
174 * 保存本地主机名、域名和DNS服务器信息的结构体:
175 * typedef struct {
176 * char HostName[MAX_HOSTNAME_LEN + 4]; // 本地计算机的主机名
177 * char DomainName[MAX_DOMAIN_NAME_LEN + 4]; // 本地计算机注册到域的名称
178 * PIP_ADDR_STRING CurrentDnsServer; // 预留变量
179 * IP_ADDR_STRING DnsServerList; // 指定本地计算机上定义的DNS服务器列表
180 * UINT NodeType; // 本地计算机的节点类型
181 * char ScopeId[MAX_SCOPE_ID_LEN + 4]; // DHCP域名
182 * UINT EnableRouting; // 指定本地计算机是否启用了路由的功能
183 * UINT EnableProxy; // 指定本地计算机是否为ARP代理
184 * UINT EnableDns; // 指定本地计算机是否启用了DNS
185 * } FIXED_INFO, *PFIXED_INFO;
186 **/
187
188 int GetNetworkParamsFunction() // 获取本地主机名、域名和DNS服务器信息
189 {
190 // 声明变量
191 FIXED_INFO * FixedInfo; // 定义保存本地计算机网络参数信息的结构体指针
192 ULONG ulOutBufLen; // 保存获取到的本地计算机网络参数信息结构体链表的长度
193 DWORD dwRetVal; // 调用GetNetworkParams()函数的返回值
194 IP_ADDR_STRING * pIPAddr; // 保存所有DNS服务器的IP地址列表
195
196 // 获取信息
197
198 FixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, sizeof( FIXED_INFO ) ); // 为FixedInfo结构体分配内存空间
199 ulOutBufLen = sizeof( FIXED_INFO ); // 初始化ulOutBufLen变量值
200
201 // 第1次调用GetNetworkParams()函数,获取返回结果的大小到ulOutBufLen中
202 if( ERROR_BUFFER_OVERFLOW == GetNetworkParams( FixedInfo, &ulOutBufLen ) ) {
203 GlobalFree( FixedInfo );
204 FixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, ulOutBufLen );
205 }
206
207 // 第2次调用GetNetworkParams()函数,以前面获取的ulOutBufLen作为参数,
208 if ( dwRetVal = GetNetworkParams( FixedInfo, &ulOutBufLen ) != ERROR_SUCCESS) {
209 printf( "调用GetNetworkParams()函数失败。返回值: %08x\n", dwRetVal );
210 }
211 else {
212 printf( "主机名: %s\n", FixedInfo->HostName );
213 printf( "域名: %s\n", FixedInfo->DomainName );
214 printf("\n==========网络信息==========\n");
215
216 // 生成节点类型字符串
217 char* NodeType;
218 switch(FixedInfo->NodeType){
219 case BROADCAST_NODETYPE: NodeType = "Broadcase Node"; break;
220 case PEER_TO_PEER_NODETYPE: NodeType = "Peer to Peer Node"; break;
221 case MIXED_NODETYPE: NodeType = "Mixed Node"; break;
222 case HYBRID_NODETYPE: NodeType = "Hybrid Node"; break;
223 default: NodeType = "Unknown Node"; break;
224 }
225
226 printf("节点类型...................:%d - %s\n", FixedInfo->NodeType, NodeType);
227 printf("是否启用路由功能...........:%s\n", (FixedInfo->EnableRouting != 0) ? "是" : "否");
228 printf("是否启用ARP代理功能........:%s\n", (FixedInfo->EnableProxy != 0) ? "是" : "否");
229 printf("是否启用DNS服务器..........:%s\n", (FixedInfo->EnableDns != 0) ? "是" : "否");
230
231 printf( "\nDNS服务器列表:\n" );
232 printf( "%s\n", FixedInfo->DnsServerList.IpAddress.String );
233
234 pIPAddr = FixedInfo->DnsServerList.Next;
235 while ( pIPAddr ) {
236 printf( "\t%s\n", pIPAddr->IpAddress.String );
237 pIPAddr = pIPAddr->Next;
238 }
239 }
240
241 printf("\n");
242 system("pause");
243 return 0;
244 }
245
246 /**
247 * 用于获取本地计算机网络接口数量的函数
248 * DWORD GetNumberOfInterfaces(
249 * _out PDWORD pdwNumIf
250 * );
251 *
252 * 用于获取本地主机名、域名和DNS服务器信息的函数
253 * DWORD GetInterfaceInfo(
254 * _out PIP_INTERFACE_INFO pIfTable, // 接受本地计算机网络接口基本信息的结构体IP_INTERFACE_INFO
255 * _inout PULONG dwOutBufLen // 接到数据的大小
256 * );
257 *
258 typedef struct _IP_INTERFACE_INFO {
259 LONG NumAdapters;
260 IP_ADAPTER_INDEX_MAP Adapter[1];
261 } IP_INTERFACE_INFO,*PIP_INTERFACE_INFO;
262
263 * 用于保存计算机网络接口信息的结构体
264 * typedfe struct _IP_ADAPTER_INDEX_MAP{
265 * ULONG Index; // 网络适配器索引号
266 * WCHAR Name[MAX_ADAPTER_NAME]; // 网络适配器名称
267 * }IP_INTERFACE_INDEX_MAP, *PIP_ADAPTER_INDEX_MAP;
268 **/
269
270 // 分配内存空间
271 #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
272 // 释放内存空间
273 #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
274
275 int GetInterfacesFunction() // 获取本地计算机网络接口的基本信息
276 {
277 // 获取网络接口的数量
278 DWORD dwNumIf; // 用于获取接口数量
279 DWORD dwRetVal; // 返回值
280 if(dwRetVal = GetNumberOfInterfaces(&dwNumIf) == NO_ERROR){
281 printf("本地网络接口数量为: %d\n", dwNumIf);
282 }
283 else{
284 printf("调用GetNumberOfInterfaces()函数时出现错误。\n");
285 }
286
287 // 获取网络接口的基本信息
288 PIP_INTERFACE_INFO pInfo; // 保存网络接口信息的结构体指针
289 ULONG ulOutBufLen = 0; // 保存获取数据的长度
290 int iReturn = 1; // 本函数的返回结果
291
292 // 第1次调用 GetInterfaceInfo,获取数据大小,保存到ulOutBufLen变量中
293 dwRetVal = GetInterfaceInfo(NULL, &ulOutBufLen);
294 if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
295 pInfo = (IP_INTERFACE_INFO *) MALLOC(ulOutBufLen);
296 if (pInfo == NULL) {
297 printf("无法分配GetInterfaceInfo函数需要的内存空间。\n");
298 return 1;
299 }
300 }
301 // 第2次调用GetInterfaceInfo函数,获取需要的实际数据
302 dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);
303 if (dwRetVal == NO_ERROR) {
304 printf("网络适配器数量: %ld\n\n", pInfo->NumAdapters);
305 for (int i = 0; i < (int) pInfo->NumAdapters; i++) {
306 printf("网络适配器索引[%d]: %ld\n", i,
307 pInfo->Adapter[i].Index);
308 printf("网络适配器名称[%d]: %ws\n\n", i,
309 pInfo->Adapter[i].Name);
310 }
311 iReturn = 0;
312 } else if (dwRetVal == ERROR_NO_DATA) {
313 printf
314 ("本地计算机上没有支持IPv4的网络适配器。\n");
315 iReturn = 0;
316 } else {
317 printf("GetInterfaceInfo调用失败: %d\n", dwRetVal);
318 iReturn = 1;
319 }
320
321 FREE(pInfo); // 释放内存空间
322 system("pause");
323 return (iReturn);
324 }
325
326
327 /**
328 * 获取本地计算机IP地址表的函数
329 * DWORD GetIpAddrTable(
330 * _out PMIB_IPADDRTABLE pIpAddrTable, // 接受获取到的本地计算机网络接口和IP地址的映射表
331 * _inout PULONG pdwSize, // 接收收到数据的大小
332 * _in BOOL bOrder // 获取到的映射表中是否按IP地址的升序排列
333 * );
334 *
335 * 用于保存IP地址表的PMIB_IPADDRTABLE结构体
336 * typedef struct _MIB_IPADDRTABLE{
337 * DWORD dwNumEntries; // 表示映射表中记录的数量
338 * MIB_IPADDRROW table[ANY_SIZE]; // MIB_IPADDRROW结构体数组
339 * }MIB_IPADDRTABLE, *PMIB_IPADDRTABLE;
340 *
341 * 用于保存IP地址的结构体
342 * typedef struct _MIB_IPADDRROW{
343 * DWORD dwAddr; // 网络字节序格式的IP地址
344 * DWORD dwIndex; // 与IP地址相关联的网络编号序号
345 * DWORD dwMask; // 网络字节序的子网掩码
346 * DWORD dwBCastAddr; // 网络字节序格式的广播地址
347 * DWORD dwReasmSize; // 已收到的数据报重装后的最大长度
348 * unsigned short unusedl; // 预留字段
349 * unsigned short wType; // IP地址的类型或状态
350 * }MIB_IPADDRROW, *PMIB_IPADDRROW;
351 **/
352
353 //#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
354 //#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
355
356 int GetIpAddrTableFunction()
357 {
358 PMIB_IPADDRTABLE pIPAddrTable; // 网络接口与IP地址映射表
359 DWORD dwSize = 0; // 获取数据的大小
360 DWORD dwRetVal = 0; // 调用GetIPAddrTable()函数的返回值
361 IN_ADDR IPAddr; // 保存IP地址的结构体
362 LPVOID lpMsgBuf; // 用于获取错误信息
363
364 // 分配内存空间
365 pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(sizeof (MIB_IPADDRTABLE));
366 // 第1次调用GetIpAddrTable()函数,获取数据的大小到dwSize
367 if (pIPAddrTable) {
368 if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
369 FREE(pIPAddrTable);
370 pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(dwSize);
371
372 }
373 if (pIPAddrTable == NULL) {
374 printf("GetIpAddrTable()函数内存分配失败\n");
375 exit(1);
376 }
377 }
378 // 第2次调用GetIpAddrTable()函数,获取实际数据
379 if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) != NO_ERROR ) {
380 printf("GetIpAddrTable()调用失败: %d\n", dwRetVal);
381 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
382 dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) & lpMsgBuf, 0, NULL)) {
383 printf("\t错误信息: %s", lpMsgBuf);
384 LocalFree(lpMsgBuf);
385 }
386 exit(1);
387 }
388
389 printf("\t记录数量: %ld\n", pIPAddrTable->dwNumEntries);
390 for (int i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
391 printf("\n\t接口序号[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
392 IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
393 printf("\tIP地址[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
394 IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
395 printf("\t子网掩码[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
396 IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
397 printf("\t广播地址[%d]: \t%s (%ld%)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
398 printf("\t重组报文最大数量[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
399 printf("\t类型和状态[%d]:", i);
400 if (pIPAddrTable->table[i].wType & MIB_IPADDR_PRIMARY) printf("\t主IP地址");
401 if (pIPAddrTable->table[i].wType & MIB_IPADDR_DYNAMIC) printf("\t动态IP地址");
402 if (pIPAddrTable->table[i].wType & MIB_IPADDR_DISCONNECTED) printf("\t断开连接的接口对应的IP地址");
403 if (pIPAddrTable->table[i].wType & MIB_IPADDR_DELETED) printf("\t删除的IP地址");
404 if (pIPAddrTable->table[i].wType & MIB_IPADDR_TRANSIENT) printf("\t临时地址");
405 printf("\n");
406 }
407
408 if (pIPAddrTable) {
409 FREE(pIPAddrTable);
410 pIPAddrTable = NULL;
411 }
412
413 printf("\n");
414 system("pause");
415 return 0;
416 }