Winsock编程接口实验

Winsock编程接口实验

实验目的

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地址列表。

流程图如下:

Winsock编程接口实验_第1张图片

\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地址。

流程图如下:

Winsock编程接口实验_第2张图片

实验流程

  1. 实验编译中遇到的情况:由于VS版本过高有些函数使用不了,需要更改VS中的一些参数设置。

.解决方案:

将图中选项修改为否就可以运行。

  1. 实验运行结果截图:
  • 实验内容1:
    Winsock编程接口实验_第3张图片
  • 实验内容2:
    Winsock编程接口实验_第4张图片

实验思考

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可以保持负载平衡,增强服务性能。

  1. 实验中遇到的问题:

由于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;

}

你可能感兴趣的:(网络编程)