1.掌握Winsock的启动和初始化;
2.掌握gethostname(),gethostbyname(),GetAdaptersInfo()等信息查询函数的使用。
1.编写程序能同时实现对多个域名的解析。比如在控制台输入:getip www.163.com www.swust.edu.cn, 能输出www.163.com和 www.swust.edu.cn对应的IP地址列表。
根据对题目的理解,我们需要实现对域名的解析,还要考虑到对多个域名的解析,这里我们可以用循环来做。
而对域名的解析需要用到gethostbyname()函数,其函数的原型为:
struct hostent *gethostbyname(const char *name);
name为指向主机名的指针,它一般由函数gethostname返回。
函数返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针,该结构格式如下:
struct hostent{
char FAR* h_name;
char FAR* FAR* h_aliases;
short h_addrtype;
short h_length;
char FAR* FAR* h_addr_list;
};
因为主机名已知的,我们只需要调用此函数就可以得到对应的ip地址列表。
流程图如下:
\2. 编写程序获取并输出本地主机的所有适配器的IP地址,子网掩码,默认网关,MAC地址。
GetAdaptersInfo()该函数可以获取本地主机的所有适配器信息,并保存在pAdapterInfo所指向的链表中。
函数原型为:
DWORD GetAdaptersInfo(
IP_ADAPTER_INFO pAdapterInfo, // buffer to receive data
PULONG pOutBufLen // size of data returned
);
IP_ADAPTER_INFO的定义如下:
typedef struct _IP_ADAPTER_INFO {
struct _IP_ADAPTER_INFO* Next;
DWORD ComboIndex;
char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
UINT AddressLength;
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
DWORD Index;
UINT Type;
UINT DhcpEnabled;
PIP_ADDR_STRING CurrentIpAddress;
IP_ADDR_STRING IpAddressList;
IP_ADDR_STRING GatewayList;
IP_ADDR_STRING DhcpServer;
BOOL HaveWins;
IP_ADDR_STRING PrimaryWinsServer;
IP_ADDR_STRING SecondaryWinsServer;
time_t LeaseObtained;
time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
我们可以直接调用该函数就能得到本地主机的所有适配器的ip地址,子网掩码,默认网关,MAC地址。
流程图如下:
.解决方案:
将图中选项修改为否就可以运行。
1.思考题:
A:Winsock初始化的作用是什么?
答:可以使用WSAStartup载入合适的Winsock动态链接库。
B:给出GetAdaptersInfo()函数的正确使用方法。
答:其函数原型为:
DWORD GetAdaptersInfo()
该函数可以获取本地主机的所有适配器信息,并保存在pAdapterInfo所指向的链表中。函数原型为:
DWORD GetAdaptersInfo(
PIP_ADAPTER_INFO pAdapterInfo, // buffer to receive data
PULONG pOutBufLen // size of data returned
);
第一个参数pAdapterInfo是指向一个缓冲区指针,其中使用IP_ADAPTER_INFO结构体保存获取到的网络适配器信息;第二个参数pOutBufLen是一个指向ULONG变量的指针,保存pAdapterInfo缓冲区的大小。GetAdaptersInfo()函数的返回值为DWORD类型,如果函数调用成功,则返回ERROR_SUCCESS;否则将返回错误编码。
C:域名解析时出现域名对应多个IP,请解释原因。
答:使用多个ip可以保持负载平衡,增强服务性能。
由于vs版本过高代码运行不成功
这次实验使我基本上对Winsock有了一个基本的认识,知道了如何去使用命令去了解本机的相关知识,对计算机通信有了更深层次的理解。在答辩时老师会考察相关代码的理解能力,所以让我们不仅仅是停留在得出结果的层面,更让我们去深入理解每行代码的意思,这也是每个程序员所要具备的基本技能。让我不仅知其然更知其所以然,提高了我对Winsock的学习热情。虽然对有些知识还有些模棱两可,需要我自己在书上去了解,但是万变不离其宗,都是需要自己日积月累的,要下去学习的!
实验一代码:
#include
#include
#include
// winsock2 头文件 和 ws2_32库文件
#pragma comment(lib,“WS2_32”)
using namespace std;
int main()
{
string message; //获取本地主机名
WSADATA wsaData; //初始化winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
exit(0);
}
while (true)
{
cout << “请输入域名:” << endl;
cin >> message;
// 创建一个存放gethostbyname函数结果的结构体
hostent *host = gethostbyname(message.c_str());
for (int i = 0; ; i++)
{
char *p = host->h_addr_list[i];
if (p == NULL)
{
break;
}
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = *(u_long *)host->h_addr_list[i];
cout << “IP地址:” << inet_ntoa(addr.sin_addr) << endl;
}
}
if (WSACleanup() == SOCKET_ERROR)
{
cout << “WSACleanup出错!!!” << endl;
}
}
实验二代码:
#include
#include
#include
using namespace std;
#pragma comment(lib,“Iphlpapi.lib”) //需要添加Iphlpapi.lib库
int main(int argc, char* argv[])
{
//PIP_ADAPTER_INFO结构体指针存储本机网卡信息
PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
//得到结构体大小,用于GetAdaptersInfo参数
unsigned long stSize = sizeof(IP_ADAPTER_INFO);
//调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量;其中stSize参数既是一个输入量也是一个输出量
int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
//记录网卡数量
int netCardNum = 0;
//记录每张网卡上的IP地址数量
int IPnumPerNetCard = 0;
if (ERROR_BUFFER_OVERFLOW == nRel)
{
//如果函数返回的是ERROR_BUFFER_OVERFLOW
//则说明GetAdaptersInfo参数传递的内存空间不够,同时其传出stSize,表示需要的空间大小
//这也是说明为什么stSize既是一个输入量也是一个输出量
//释放原来的内存空间
delete pIpAdapterInfo;
//重新申请内存空间用来存储所有网卡信息
pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
//再次调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量
nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
}
if (ERROR_SUCCESS == nRel)
{
//输出网卡信息
//可能有多网卡,因此通过循环去判断
while (pIpAdapterInfo)
{
cout << “网卡MAC地址:”;
for (DWORD i = 0; i < pIpAdapterInfo->AddressLength; i++)
if (i < pIpAdapterInfo->AddressLength - 1)
{
printf("%02X-", pIpAdapterInfo->Address[i]);
}
else
{
printf("%02X\n", pIpAdapterInfo->Address[i]);
}
//可能网卡有多IP,因此通过循环去判断
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
do
{
cout << “IP 地址:” << pIpAddrString->IpAddress.String << endl;
cout << “子网地址:” << pIpAddrString->IpMask.String << endl;
cout << “网关地址:” << pIpAdapterInfo->GatewayList.IpAddress.String << endl;
pIpAddrString = pIpAddrString->Next;
} while (pIpAddrString);
pIpAdapterInfo = pIpAdapterInfo->Next;
cout << “--------------------------------------------------------------------” << endl;
}
system(“pause”);
}
//释放内存空间
if (pIpAdapterInfo)
{
delete pIpAdapterInfo;
}
return 0;
}