Windows网络编程之Winsock 编程接口实验
2017-04-08 13:25
831 查看
实验一 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<stdio.h> #include<WINSOCK2.H> #include<string.h> #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地址 ch 4000 ar *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; };*/
运行结果:
第二题代码:
// GetIPConfig.cpp : 定义控制台应用程序的入口点。 // //#include "stdafx.h" #pragma comment(lib, "IPHLPAPI.lib") #include <winsock2.h> #include <iphlpapi.h> #include <stdio.h> 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网络编程笔记4 -- Winsock 协议相关知识
- 十年一遇的奇葩故障--Windows网络编程接口故障:telnet显示无法加载或初始化请求的服务提供程序
- Windows的网络编程-之一-WinSock基础
- Windows的网络编程-之一-WinSock基础
- windows编程学习--网络编程学习--winsock编程(1)
- Windows网络编程笔记之一:winsock简介
- windows编程--网络编程学习--winsock编程(2)
- windows网络编程之 (三) - Winsock非阻塞select模式服务器
- windows网络编程之Winsock(三)非阻塞select模式服务器
- Windows网络编程之winsock实现文件传输示例
- SOCKETS规范及应用-WINDOWS网络编程接口
- Windows网络编程之WinSock编程基础
- Windows下C语言网络编程快速入门
- 利用WinSock实现简单网络编程
- 网络编程--WINSOCK
- 【Windows编程】【网络编程】【基于网络端口通信的客户端应用程序】解决方案【示意程序】
- Window网络编程之Winsock(一)起步
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- Windows下C语言网络编程快速入门
- Windows 网络编程(8).1