【实验目的】
掌握Visual Studio控制台应用编程的基本方法
掌握Windows Sockets DLL的初始化和释放方法
掌握Windows Sockets API调用的一般步骤
使用Windows Sockets的API函数获得指定机器的信息
(包括主机名、服务名、IP地址)
Winsocket代码:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#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;//定义host entry结构体指针变量,定义见书p48。
char* host_name;
struct in_addr addr; //以各种形式存放4个字节的IPv4地址
char** pAlias; //定义别名列表指针变量
// Validate the parameters
if (argc != 2) { //为何argc要等于2?,程序运行时每个参数分别是什么?
printf("usage: GetHostIP hostname\n"); //提示程序运行时需要输入主机名作为参数
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);//与操作系统确认支持的WinSock版本
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);
//获取主机的信息存放在hostent结构体中。该函数调用DNS系统来获取对应域名或主机名的相关信息,可以通过Wireshark抓包来进行验证。
//对返回结果进行判断
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");
}
}
iResult = WSACleanup();//与操作系统确认支持的WinSock版本
if (iResult != 0) {
printf("WSACleanup failed: %d\n", iResult);
return 1;
}
return 0;
}
更改命令行参数:
执行结果:
通过调用接口函数getservbyport()获取结构体信息struct servent*
代码展示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h> // 此头文件放在<winsock2.h>或<ws2tcpip.h>之后
#pragma comment(lib, "ws2_32.lib") //连接静态库
int main(int argc, char** argv)
{
WSADATA wsaData; // 创建WSADATA的对象,存放socket版本号等信息
int iResult; // 接收WSAStarup()函数的返回值
struct servent* remoteServ;
/* -------------------------*/
// 注册套接字
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);//与操作系统确认支持的WinSock版本
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
short num = 1;
printf("打印端口服务内容:\n");
while (num < (unsigned short)-1) // 65535
{
remoteServ = getservbyport(htons((u_short)num), "tcp"); // 服务端口,按网络字节顺序排列
if (NULL == remoteServ);// printf("error %d ,please continue.\n", num);
else {
printf("服务名: %s \n", remoteServ->s_name);
printf("端口号: %d \n", ntohs((u_short)remoteServ->s_port)); //端口号按网络字节顺序返回
printf("协议名: %s \n\n", remoteServ->s_proto);
}
num++;
}
/* -------------------------*/
// 释放资源
iResult = WSACleanup();
if (iResult != 0) {
printf("WSACleanup failed: %d\n", iResult);
return 1;
}
return 0;
}
执行结果: