TCP/IP编程:DNS域名解析

一、地址转换总体思路
  1. 深入底层,地址还是二进制形式,只是存储方式有小端还有大端形式;
  2. 表示给用户时:点分十进制数表示的IP地址转换成网络字节顺序的IP地址
  3. 网络实际传输时:主机字节顺序转成网络字节顺序
  4. 根据用户需要,
    展示:将小端或或者大端方式存储的二进制形式,转成十进制或者十六进制形式展现出来
    传递:或者转成网络字节顺序,在网络上传输。
二、inet_addr()
1. 点分十进制数表示的IP地址转换成网络字节顺序的IP地址
#include <iostream>
#include <Winsock2.h>
#pragma comment(lib, "wsock32.lib")

using namespace std;

int main()
{
	unsigned long IP;
	IP =inet_addr("192.168.0.1");
	cout << IP << endl;
	system("Pause");
	return 0;
}

1.1 出现错误:

错误 C4996 ‘inet_addr’: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings DSN Domain Resolution H:\source\TCP\DSN Domain Resolution\DSN Domain Resolution\main.cpp 13

1.2 错误图片 :C4996C4996
1.3 解决办法:更改SDL检查为否
更改SDL检查为否

三、主机字节顺序转成网络字节顺序
  1. 源码:
#include <Winsock2.h>
#include <iostream>
#pragma comment(lib,"wsock.lib")

using namespace std;

int main()
{		
	unsigned long hostaddr=0xAABBCCDD;	// 定义本机字节AABBCCDD
	unsigned long netaddr;			// 定义网络字节
	netaddr=htonl(hostaddr);		// 使用函数htonl()进行转换 host to net 
	cout<<"hostaddr:"<<hostaddr<<endl;	// 输出hostaddr
	cout<<"netaddr:"<<netaddr<<endl;	// 输出netaddr
	system("Pause");
	return 0;
}
  1. 实验结果
四、网络信息获取函数应用实例

来源:《TCP/IP协议与网络编程》 任泰明 编著
DNS解析数据流动方向:

  1. hostname 获取主机名字-> 2. hostent 获取主机信息-> 3. pHostent->h_addr_list[n] 解析地址 -> 4. pProtoent 展示协议信息
hostent内容

-> name 主机名字
-> aliase 主机别名
-> addrtype 地址类型
-> length 地址长度(字节)
-> addr_list[n]

addr_list[n]内容

addr_list[n](IP列表,IP地址是4个字节,32位,
这里获取的IP地址是网络字节顺序,
通过inet_ntoa(sa.sin_addr)函数,将其转换成点分十进制数表示的IP地址

注意:这里使用了memcpy()函数,直接复制32位内存,即IP地址,
猜想可能和小端方式,大端方式有关,
即无论我是小端方式,还是大端方式,都直接复制过来。
但windows系统规定了是小端方式,
所以,它的转换函数inet_ntoa(sa.in_addr)也是针对小端方式来设计的)

1. 源码
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "wsock32.lib")

int main()
{
	WSADATA wsaData;
	int		n;
	// 存放主机名称
	char	hostname[256];
	// 主机信息指针
	hostent* pHostent;
	// 主机协议信息指针
	protoent* pProtoent;
	// sockaddr_in结构指端口和IP地址信息	
	struct sockaddr_in sa;
	// 其实 不用struct也能够成功执行
	// sockaddr_in sa; 
	if (WSAStartup(MAKEWORD(2, 2), &wsaData )!= 0) 
	{
		printf("Failed to load Winsock.\n");
		return -1;
	}

	printf("-----------------------------------------------\n");
	// 获得主机名
	if (gethostname(hostname, sizeof(hostname)) != 0) 
	{
		printf("gethostname() Error:%u\n",WSAGetLastError());
		return -2;
	}
	printf("以下信息由gethostname()函数取得\n");
	printf("Local host name:%s\n",hostname);
	printf("------------------------------------------------\n");
	// 根据主机名获取主机信息
	pHostent = gethostbyname(hostname);
	if (pHostent == NULL)
	{
		printf("gethostbyname()Error:%u\n",WSAGetLastError());
		return -3;
	}
	// 解析返回的hostent结构中名称、别名、地址类型和地址长度信息
	printf("以下信息由gethostbyname()函数取得\n");
	printf("name:%s\naliases:%s\naddrtype:%d\nlength:%d\n",
		pHostent->h_name,
		pHostent->h_aliases,
		pHostent->h_addrtype,
		pHostent->h_length);
	// 解析hostent结构中的主机地址
	for (n = 0; pHostent->h_addr_list[n]; n++)
	{
		// memcpy函数在C/C++中都可以使用 内存拷贝函数
		/* 
		memcpy指的是C和C++使用的内存拷贝函数,
		函数原型为void *memcpy(void *destin, void *source, unsigned n);
		函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,
		即从源source中拷贝n个字节到目标destin中。
		*/
		memcpy(&sa.sin_addr.s_addr,pHostent->h_addr_list[n],pHostent->h_length);
		// 输出主机IP地址。
		printf("Address:%s\n",inet_ntoa(sa.sin_addr));
	}
	printf("-------------------------------------------------\n");
	// 根据协议名获得协议信息
	pProtoent = getprotobyname("tcp");
	if (pProtoent == NULL) 
	{
		printf("getprotobyname()Error:%u\n", WSAGetLastError());
		return -4;
	}
	// 解析protoent结构中的信息
	printf("以下信息由getprotobyname()函数取得\n");
	printf("name:%s\nproto:%d\n",
		pProtoent->p_name,
		pProtoent->p_proto);
	for (n = 0; pProtoent->p_aliases[n]; n++) 
	{
		printf("aliases:%s\n",pProtoent->p_aliases[n]);
	}
	WSACleanup();

	system("Pause");
	return 0;
}

2. 应用

DNS域名解析

3. 问题:
  1. 获取本地主机名和IP地址如何实现?上面实例是获取本地主机名,和DNS解析还有一定差距,应该是采用下面的应用,探索ing。
  2. 获取网络主机名和IP地址又如何实现?在此基础上完成DNS域名解析?
  3. DNS域名解析和ping工具有什么联系吗?

Winsock API基本函数

1. WinSock的初始化:
  1. 任何基于Winsock的程序,首先要将正确的Winsock的DLL装入到内存中。如Winsock2的应用程序,则要加载ws2_32.dll文件
2. 应用:
# pragma comment(lib, "wsock32.lib")
2. Winsock的打开——WSAStartup()
功能:
  1. 加载响应的WinSock的dll版本。在使用WinSock函数前,若没有加载WinSock库,则函数就会返回一个SOCKET_ERROR
  2. 通过调用WSAStartup()函数便可检测系统中有没有一个或者多个Windows Sockets实现。
  3. 本函数必须是应用程序或DLL调用的第一个Windows Sockets函数,它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Socket实现的细节。
  4. 应用程序或DLL只能在一次成功的WSAStartup()调用之后才能进一步调用其他的Windows Sockets API函数。
应用:
  1. C++空项目
  2. Win32应用程序

一、C++ 空项目

# include <stdio.h>
# include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
	WORD wVersionRequested;
	WSAData wsaData;
	wVersionRequested = MAKEWORD(2, 2);
	// 打开winsock WSAData 
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		// Winsock 初始化错误 !
		// 输出Winsock初始化错误信息,如“WSAStartup failed”
		MessageBox(NULL, "Initialization error!\n WSAStartup failed!", "Intialization error!", 0);
		return -1;
	}
	// 以下两种方法中的任意一种进行版本号匹配的检查
	// 版本号是两字节 
	// 判断高字节HIBYTE==2 低字节LOBYTE==2
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		MessageBox(NULL, "Winsock2装载的版本不对!", "WSAStartup", 0);
		WSACleanup();
		return -1;
	}

	char data[400];
	sprintf_s(data, 400, "WSAStartup装载成功!\n版本是:%d,%d\n描述:%s\n状态:",
		HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion), wsaData.szDescription, wsaData.szSystemStatus);

	MessageBox(NULL, data, "装载WSAStartup", 0);

	WSACleanup();
	return 0;
}

C++空项目
二、 Win32应用程序

#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

	WORD wVersionRequested;
	WSAData wsaData;
	wVersionRequested = MAKEWORD(2, 2);
	// 打开winsock WSAData 
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		// Winsock 初始化错误 !
		// 输出Winsock初始化错误信息,如“WSAStartup failed”
		MessageBox(NULL, "Initialization error!\n WSAStartup failed!","Intialization error!",0);
		return -1;
	}
	// 以下两种方法中的任意一种进行版本号匹配的检查
	// 版本号是两字节 
	// 判断高字节HIBYTE==2 低字节LOBYTE==2
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		MessageBox(NULL, "Winsock2装载的版本不对!", "WSAStartup", 0);
		WSACleanup();
		return -1;
	}

	char data[400];
	sprintf_s(data,400,"WSAStartup装载成功!\n版本是:%d,%d\n描述:%s\n状态:%s",
		HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion),wsaData.szDescription,wsaData.szSystemStatus);

	MessageBox(NULL,data ,"装载WSAStartup",0);

	WSACleanup();
	
	return 0;
}

Win32应用程序

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值