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 }