Windows网络编程之Winsock 编程接口实验

实验一 Winsock 编程接口实验

1 实验类型
验证型实验
2 实验目的
1. 掌握Winsock 的启动和初始化;
2. 掌握gethostname(),gethostbyname(),GetAdaptersInfo()等信息查询函数的使用。
3 背景知识
(1)Winsock 基本概念
Winsock 即Windows Sockets 的简称,是在Windows 操作系统平台下使用的套接字接口。
自Winsock2 规范开始,Windows Sockets 就成为了一个得到广泛应用的、开放的、支持多种
协议的网络编程接口。它是一个与协议无关的传送接口,可以用该接口来调用大多数网络协
议,而不需要知道这些协议具体的实现细节。
Win32 平台下的Winsock 编程接口支持的协议包括:IP、IPX/SPX、NetBIOS、AppleTalk、
ATM 等,这些协议具有相当大的差异,例如它们支持不同范围的网络、不同的寻址方式、
不同的传输介质等,但它们的调用操作大多数是相同的。因此,定义统一的Winsock 编程接
口,有利于实现采用统一的方法对实现对不同协议的调用,简化网络程序设计过程。
Winsock编程接口的实质是一套AP(I Application Programming Interface,应用编程接口),
称为Winsock API,由一系列函数构成。在编写网络程序的时候,经常需要跟这些函数打交
道,通过对这些函数的调用,实现对具体网络协议的控制,达到实现网络事务的目的。
(2)Winsock 的启动和终止
由于Winsock 的服务是以动态链接库Winsock DLL(在Windows 安装目录下的system32
下,假如Windows 安装在C:\WINNT 目录下,则在C:\WINNT\ system32 目录下可以找到
winsock.dll)形式实现的,因此必须先调用WSAStartup 函数实现对Winsock DLL 的初始化,
协商Winsock 的版本,并分配必要的资源。
WSAStartup 函数原型为:
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
其中,参数wVersionRequested 用于指定准备加载的Winsock 库的版本;通常的做法是
高位字节指定所需要的Winsock 库的副版本,低位字节指定所需要的Winsock 库的主版本,
后,再用宏MAKEWORD(X,Y)(X 是低位字节,Y 是高位字节)获得wVersionRequested
的正确值。
lpWSAData 参数是指向LPWSADATA 结构的指针,该结构包含了加载的库版本的有关
信息,具体格式如下:
Typedef struct WSAData{
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
}WSADATA, *LPWSADATA;
其中,wVersion 字段为希望使用的Winsock 版本。字段wHighVersion 返回现有Winsock
库的最高版本。szDescription 和szSystemStatus 这两个字段由特定的Winsock 实施方案设定,
事实上没有使用。字段iMaxSockets 和iMaxUdpDg 分别为可同时打开的套接字数和数据报
的最大长度,一般不要使用它们,若想知道数据报的最大长度则应该通过WSAEnumProtocols
函数来查询协议信息,而可同时打开套接字的最大数目是不固定的,它很大程度上和可用物
理内存的数量有关。最后一个字段lpVendorInfo 是为厂商预留的,任何一个Win32 平台都没
有使用这个字段。
此外,在应用程序关闭套接字后,还应调用WSACleanup 函数终止对Winsock DLL 的使
用,并释放资源,以备下次使用。
WSACleanup 函数的原型如下:
int WSACleanup(void);
该函数不带任何参数,若调用成功则返回0,否则返回错误。
(3)信息查询函数
1)gethostname()
函数原型为:
int gethostname(char *name, int namelen);
name 是一个指向将要存放主机名的缓冲区指针。
namelen 用于指定缓冲区的长度。
该函数把本地主机名存入由name 参数指定的缓冲区中,返回的主机名是一个以
NULL 结束的字符串。
2) 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;
};
3)DWORD GetAdaptersInfo()
该函数可以获取本地主机的所有适配器信息,并保存在pAdapterInfo 所指向的链表
中。函数原型为:
DWORD GetAdaptersInfo(
PIP_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;
4 实验内容
1、编写程序能同时实现对多个域名的解析。比如在控制台输入:getip www.163.com
www.swust.edu.cn, 能输出www.163.com 和 www.swust.edu.cn 对应的IP 地址列表。
2、编写程序获取并输出本地主机的所有适配器的IP 地址,子网掩码,默认网关,MAC地址。

                              下面是代码部分:

1.第一题代码:

#include
#include
#include
#pragma comment(lib,"WS2_32.lib")
int main(){
char hostIp[300];  //取得主机名称
WSADATA WSAData;
if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0){
exit(1);
}                   //初始化

printf("请输入要解析的域名:");

gets(hostIp);
hostent *pHost=gethostbyname(hostIp);

if(pHost==NULL){
    printf("少年,你确定你输入的域名是正确的???\n"); //若输入错误的域名,则程序结束并提示
return -1;
}
in_addr addr; //in_addr是一个结构体,用来保存网络字节顺序格式的IP地址
for(int i=0;;i++){         //循环的作用是,有可能一个域名对应多个IP地址
    char *p=pHost->h_addr_list[i];
    if(p==NULL){
    break;       
    } //当解析完成,程序退出
    memcpy(&addr.S_un.S_addr,p,pHost->h_length);//内存拷贝函数,将p内存地址的起始位置拷贝pHost->h_length个字节到源地址&addr.S_un.S_addr中去
    char *addIp=inet_ntoa(addr);//将网络地址转换为点分十进制的IP地址格式
    printf("\n域名:%s\nIP地址:%s\n",hostIp,addIp);
    printf("服务器名字:%s\n",pHost->h_name);
    return 0;

}         
WSACleanup();

}
   /*  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;
};*/

运行结果:
Windows网络编程之Winsock 编程接口实验_第1张图片

第二题代码:

// GetIPConfig.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"
#pragma comment(lib, "IPHLPAPI.lib") 
#include  
#include  
#include  

int main(int argc, char* 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中
    int err=GetAdaptersInfo(pAdapterInfo,
        &ulOutBufLen);
    if( err!= ERROR_SUCCESS)
    {
        printf("error one\n");
        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<(int)pAdapter->AddressLength; i++)
        {
            if(i==(int)(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;
}

Windows网络编程之Winsock 编程接口实验_第2张图片

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