实验五 获取网络信息
一、 实验目的
- 掌握主要的Winsock信息查询函数的功能和用法。
- 掌握IP Helper API提供的主要功能和编程方法步骤。
二、实验内容
1.Winsock信息查询函数:
(1)根据域名获取远程计算机的IP地址;
(2)获取本机的IP地址。
2.使用IP Helper API获取本机的网络配置信息:
(1)获取本机的MAC地址、IP地址、子网掩码等网络适配器信息。
(2)获取本地主机名、域名和DNS服务器信息。
(3)获取本地计算机IP地址表。
三、实验原理
(1) gethostname()
主要功能:返回本地主机的标准主机名。
主要参数:一个缓冲区指针 *name和一个int类型的变量namelen,表示缓冲区的长度。
如果没有错误发生,gethostname()返回0。否则它返回SOCKET_ERROR。
数据结构:字符类型的数组。
(2) gethostbyaddr()
主要功能:返回对应于给定地址的主机信息。
主要参数:add指向网络字节顺序地址的指针、lenth 地址长度和type 地址类型,因为是针对ipv4 所以这边默认为 PE_INET。
如果没有错误发生,gethostbyaddr()返回如上所述的一个指向hostent结构的指针,否则,返回一个空指针
数据结构:需要定义一个名为hostent的结构体,用于函数返回,该结构是一个list列表,用于保存主机地址,顺序存储
(3) gethostbyname()
主要功能:通过主机名字获取主机名字和地址等信息
主要参数:const char FAR * addr 一个指向主机名的指针。
返回值:如果没有错误发生,gethostbyname()返回一个指向hostent结构的指针,否则,返回一个空指针
数据结构:需要定义一个名为hostent的结构体,用于函数返回,该结构是一个list列表,用于保存主机地址,顺序存储
(4) getprotobyname()
主要功能:通过协议名获取协议名和协议号等信息
主要参数:一个指向协议名的指针
返回值: 如果没有错误发生,getprotobyname()返回如上所述的一个指向protoent结构的指针,否则,返回一个空指针
数据结构:需要定义一个名为protoent的结构体,用于函数返回,该结构是一个list列表,用于保存协议信息
(5) getprotobynumber()
主要功能 返回对应于给定协议号的相关协议信息。
主要参数:一个指向协议名的指针。
返回值: 如果没有错误发生,getprotobynumber()返回如上所述的一个指向protoent结构的指针,否则,返回一个空指针。
数据结构:需要定义一个名为protoent的结构体,用于函数返回,该结构是一个list列表,用于保存协议信息。(同4)
(6) getservbyname()
主要功能:返回对应于给定服务名和协议名的相关服务信息
主要参数 一个指向服务名的指针和一个可选的指向协议名的指针
返回值 如果没有错误发生,getservbyname()返回如上所述的一个指向servent结构的指针,否则,返回一个空指针
数据结构:需要定义一个名为servent的结构体,用于函数返回,该结构是一个list列表,用于保存服务器信息。
(7) getservbyport()
主要功能:返回对应于给定端口号和协议名的相关服务信息。
主要参数:给定的端口号,以网络字节顺序排列和指向协议名的指针(可选)
返回值 如果没有错误发生,getservbyport()返回如上所述的一个指向servent结构的指针,否则,返回一个空指针
数据结构 需要定义一个名为servent的结构体,用于函数返回,该结构是一个list列表,用于保存服务器信息,同(6)
四、实验步骤
(1)根据域名获取远程计算机的IP地址
1.首先调用库函数
2.在调用gethostbyname获取ip地址时,必须先调用WSASTART进行初始化,否则会报一个WSANOTINTIALISED错误
- 调用gethostbyname()获取指定主机名的主机信息,并对错误信息进行分析,若出现错误,将错误打印出来;若正常运行,将主机名对应的官方名称、别名、IP地址类型、IP地址长度、地址列表都打印出来。本次实验笔者对www.baidu.com进行了解析,实验结果如下。
(2)获取本机的IP地址
该实验和(1)实验实现过程基本相似,区别是获取本地的ip地址用到的函数是gethostname函数
最后获得的结果是
(3)获取本机的MAC地址、IP地址、子网掩码等网络适配器信息。
-
是前几个实验不同的是,在调用该函数进行分析时,需要声明头文件
-
之后在声明完变量后,创建一个链表pAdapterInfo,并为其分配空间,用于存储获取到的信息。
-
两次调用getAdapterInfo函数,第一次调用获取返回数据大小, 第二调用需要将第一次调用获取的数据大小作为参数,获取真正的结构体信息。
-
成功获取信息后,将链表中的信息打印出来,下面是笔者电脑上的信息。释放资源。
(4)获取本地主机名、域名和DNS服务器信息。
该实验的实现方法和(3)类似,都需要两次调用函数,本次需要调用GetNetworkparams,第二次将第一次的返回结果作为参数,来获取真实的结构体内容。获取结果存放在链表中;最后,打印完成后,将资源释放。
最后获取到本机结果是:
(5)获取本地计算机IP地址表。
在获取本地计算机ip地址表时,需要调用的函数是:GetIpAddrTable(),也是需要进行两次调用,第一次结果作为第二次参数进行调用,获取实际数据;然后将结构体的数据打印出来,需要将DWORD类型的IP地址转换为字符串。最后释放资源。
最后实验结果是:
五、实验小结
附:程序源代码
(1)根据域名获取远程计算机的IP地址;
#include "stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char **argv)
{
//-----------------------------------------
// Declare and initialize variables
WSADATA wsaData;
int iResult;
DWORD dwError;
int i = 0;
struct hostent *remoteHost;
char *host_name;
struct in_addr addr;
char **pAlias;
// Validate the parameters
if (argc != 2) {
printf("usage: GetHostIP hostname\n");
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
host_name = argv[1];
printf("Calling gethostbyname with %s\n", host_name);
remoteHost = gethostbyname(host_name);
if (remoteHost == NULL) {
dwError = WSAGetLastError();
if (dwError != 0) {
if (dwError == WSAHOST_NOT_FOUND) {
printf("Host not found\n");
return 1;
} else if (dwError == WSANO_DATA) {
printf("No data record found\n");
return 1;
} else {
printf("Function failed with error: %ld\n", dwError);
return 1;
}
}
} else {
printf("Function returned:\n");
printf("\t Official name: %s\n", remoteHost->h_name);
for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++) {
printf("\tAlternate name #%d: %s\n", ++i, *pAlias);
}
printf("\tAddress type: ");
switch (remoteHost->h_addrtype) {
case AF_INET:
printf("AF_INET\n");
break;
case AF_NETBIOS:
printf("AF_NETBIOS\n");
break;
default:
printf(" %d\n", remoteHost->h_addrtype);
break;
}
printf("\tAddress length: %d\n", remoteHost->h_length);
i = 0;
if (remoteHost->h_addrtype == AF_INET)
{
while (remoteHost->h_addr_list[i] != 0) {
addr.s_addr = *(u_long *) remoteHost->h_addr_list[i++];
printf("\tIP Address #%d: %s\n", i, inet_ntoa(addr));
}
}
else if (remoteHost->h_addrtype == AF_NETBIOS)
{
printf("NETBIOS address was returned\n");
}
}
system("pause");
WSACleanup();
return 0;
}
(2)获取本机的IP地址。
#include "stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char **argv)
{
//-----------------------------------------
// Declare and initialize variables
WSADATA wsaData;
int iResult;
DWORD dwError;
int i = 0;
struct hostent *remoteHost;
char host_name[256];
struct in_addr addr;
char **pAlias;
// Validate the parameters
if (argc != 1) {
printf("usage: GetLocalIP \n");
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
iResult = gethostname( host_name, sizeof( host_name ));
if (iResult !=0) {
printf("gethostname failed: %d\n",iResult);
return 1;
}
printf("Calling gethostbyname with %s\n", host_name);
remoteHost = gethostbyname(host_name);
if (remoteHost == NULL) {
dwError = WSAGetLastError();
if (dwError != 0) {
if (dwError == WSAHOST_NOT_FOUND) {
printf("Host not found\n");
return 1;
} else if (dwError == WSANO_DATA) {
printf("No data record found\n");
return 1;
} else {
printf("Function failed with error: %ld\n", dwError);
return 1;
}
}
} else {
printf("Function returned:\n");
printf("\tOfficial name: %s\n", remoteHost->h_name);
for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++) {
printf("\tAlternate name #%d: %s\n", ++i, *pAlias);
}
printf("\tAddress type: ");
switch (remoteHost->h_addrtype) {
case AF_INET:
printf("AF_INET\n");
break;
case AF_NETBIOS:
printf("AF_NETBIOS\n");
break;
default:
printf(" %d\n", remoteHost->h_addrtype);
break;
}
printf("\tAddress length: %d\n", remoteHost->h_length);
i = 0;
if (remoteHost->h_addrtype == AF_INET)
{
while (remoteHost->h_addr_list[i] != 0) {
addr.s_addr = *(u_long *) remoteHost->h_addr_list[i++];
printf("\tIP Address #%d: %s\n", i, inet_ntoa(addr));
}
}
else if (remoteHost->h_addrtype == AF_NETBIOS)
{
printf("NETBIOS address was returned\n");
}
}
return 0;
}
(3)获取本机的MAC地址、IP地址、子网掩码等网络适配器信息。
#include "stdafx.h"
#pragma comment(lib, "IPHLPAPI.lib")
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
IP_ADAPTER_INFO *pAdapterInfo;
ULONG ulOutBufLen;
DWORD dwRetVal;
PIP_ADAPTER_INFO pAdapter;
// 为pAdapterInfo分配空间
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
// 第1次调用GetAdaptersInfo(),获取返回结果的大小到ulOutBufLen中
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS)
{
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
}
// 第2次调用GetAdaptersInfo(),获取本地网络信息到结构体pAdapterInfo中
if((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS)
{
printf("GetAdaptersInfo Error! %d\n", dwRetVal);
}
// 从pAdapterInfo 获取并显示本地网络信息
pAdapter = pAdapterInfo;
while(pAdapter)
{
printf("网络适配器名: \t\t%s\n", pAdapter->AdapterName);
printf("网络适配器描述: \t%s\n\n", pAdapter->Description);
printf("MAC地址: \t\t");
for(int i=0; i<pAdapter->AddressLength; i++)
{
if(i==(pAdapter->AddressLength -1))
printf("%.2X\n", (int)pAdapter->Address[i]);
else
printf("%.2X-", (int)pAdapter->Address[i]);
}
printf("IP地址: \t\t%s\n", pAdapter->IpAddressList.IpAddress.String);
printf("子网掩码: \t\t%s\n", pAdapter->IpAddressList.IpMask.String);
printf("网关: \t\t\t%s\n", pAdapter->GatewayList.IpAddress.String);
printf("********************************************************************\n");
if(pAdapter->DhcpEnabled)
{
printf("启用DHCP: \t\t是\n");
printf("DHCP服务器: \t\t%s\n", pAdapter->DhcpServer.IpAddress.String);
}
else
{
printf("启用DHCP: \t\t否\n");
}
// 处理下一人网络适配器
pAdapter = pAdapter->Next;
}
// 释放资源
if(pAdapterInfo)
free(pAdapterInfo);
printf("\n\n");
system("pause");
return 0;
}
(4)获取本地主机名、域名和DNS服务器信息。
// GetNetworkParams.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "IPHLPAPI.lib")
int _tmain(int argc, _TCHAR* argv[])
{
FIXED_INFO * FixedInfo;
ULONG ulOutBufLen;
DWORD dwRetVal;
IP_ADDR_STRING * pIPAddr;
// 为FixedInfo结构体分配内存空间
FixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, sizeof( FIXED_INFO ) );
// 初始化ulOutBufLen变量值
ulOutBufLen = sizeof( FIXED_INFO );
// 第1次调用GetNetworkParams()函数,获取返回结果的大小到ulOutBufLen中
if( ERROR_BUFFER_OVERFLOW == GetNetworkParams( FixedInfo, &ulOutBufLen ) ) {
GlobalFree( FixedInfo );
FixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, ulOutBufLen );
}
// 第2次调用GetNetworkParams()函数,以前面获取的ulOutBufLen作为参数,
if ( dwRetVal = GetNetworkParams( FixedInfo, &ulOutBufLen ) != ERROR_SUCCESS) {
printf( "调用GetNetworkParams()函数失败。返回值: %08x\n", dwRetVal );
}
else {
printf( "主机名: %s\n", FixedInfo->HostName );
printf( "域名: %s\n", FixedInfo->DomainName );
printf("\n==========网络信息==========\n");
// 生成节点类型字符串
char* NodeType;
switch(FixedInfo->NodeType)
{
case BROADCAST_NODETYPE:
NodeType="Broadcase Node";
break;
case PEER_TO_PEER_NODETYPE:
NodeType="Peer to Peer Node";
break;
case MIXED_NODETYPE:
NodeType="Mixed Node";
break;
case HYBRID_NODETYPE:
NodeType="Hybrid Node";
break;
default:
NodeType="Unknown Node";
break;
}
printf("节点类型...................:%d - %s\n", FixedInfo->NodeType, NodeType);
printf("是否启用路由功能...........:%s\n", (FixedInfo->EnableRouting != 0) ? "是" : "否");
printf("是否启用ARP代理功能........:%s\n", (FixedInfo->EnableProxy != 0) ? "是" : "否");
printf("是否启用DNS服务器..........:%s\n", (FixedInfo->EnableDns != 0) ? "是" : "否");
printf( "\nDNS服务器列表:\n" );
printf( "%s\n", FixedInfo->DnsServerList.IpAddress.String );
pIPAddr = FixedInfo->DnsServerList.Next;
while ( pIPAddr ) {
printf( "\t%s\n", pIPAddr->IpAddress.String );
pIPAddr = pIPAddr->Next;
}
}
printf("\n\n");
system("pause");
return 0;
}
(5)获取本地计算机IP地址表。
// GetIpAddrTable.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
int _tmain(int argc, _TCHAR* argv[])
{
int i;
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;
LPVOID lpMsgBuf;
// 分配内存空间
pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(sizeof (MIB_IPADDRTABLE));
// 第1次调用GetIpAddrTable()函数,获取数据的大小到dwSize
if (pIPAddrTable) {
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) ==
ERROR_INSUFFICIENT_BUFFER) {
FREE(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) MALLOC(dwSize);
}
if (pIPAddrTable == NULL) {
printf("GetIpAddrTable()函数内存分配失败\n");
exit(1);
}
}
// 第2次调用GetIpAddrTable()函数,获取实际数据
if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) != NO_ERROR ) {
printf("GetIpAddrTable()调用失败: %d\n", dwRetVal);
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) & lpMsgBuf, 0, NULL)) {
printf("\t错误信息: %s", lpMsgBuf);
LocalFree(lpMsgBuf);
}
exit(1);
}
printf("\t记录数量: %ld\n", pIPAddrTable->dwNumEntries);
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
printf("\n\t接口序号[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
printf("\tIP地址[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
printf("\t子网掩码[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
printf("\t广播地址[%d]: \t%s (%ld%)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
printf("\t重组报文最大数量[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
printf("\t类型和状态[%d]:", i);
if (pIPAddrTable->table[i].wType & MIB_IPADDR_PRIMARY)
printf("\t主IP地址");
if (pIPAddrTable->table[i].wType & MIB_IPADDR_DYNAMIC)
printf("\t动态IP地址");
if (pIPAddrTable->table[i].wType & MIB_IPADDR_DISCONNECTED)
printf("\t断开连接的接口对应的IP地址");
if (pIPAddrTable->table[i].wType & MIB_IPADDR_DELETED)
printf("\t删除的IP地址");
if (pIPAddrTable->table[i].wType & MIB_IPADDR_TRANSIENT)
printf("\t临时地址");
printf("\n");
}
if (pIPAddrTable) {
FREE(pIPAddrTable);
pIPAddrTable = NULL;
}
printf("\n");
system("pause");
return 0;
}