一、何为IP和域名?
我们知道,在网络中,所有的设备都会被分配一个地址,两台计算机要想进行通信,最基本的就是要知道他的IP地址,而IP地址就是以点分十进制组成的四组数字,关于IP的知识还有很多,比如网络号、主机号、子网掩码,这些不在本章范围内。
后来由于IP地址是一长串数字,不直观,而且用户记忆不方便,人们又发明了另一套字符型的地址方案,也就是域名,如www.baidu.com、www.jd.com,IP地址和域名是一一对应的,这份域名地址的信息存放在一个叫域名服务器(DNS,Domain name server)的主机内,如果我们想知道一个域名对应的IP地址,就可以通过域名服务器,让他进行转换,然后返回给我们。
但是要注意的是,一个IP地址可以对应多个域名,一个域名只有一个IP地址。
二、如何查询Web服务器的IP地址?
当浏览器生成HTTP消息之后,就需要和服务器建立连接,这里的消息指的是请求行、请求头、请求体,我们可以通过抓包软件,如Fiddler查看,点击raw的时候会显示具体的信息,在请求头里面可以告诉Web服务器他应该进行怎样的操作,还有请求的具体资源,请求头是以键:值的形式存在多个,比如我们常用的Cookie,就会放在这里面。请求数据一般在
POST方式中使用,用来发送如网页表单的数据。
生成之后,就需要向Web服务器发送数据,但是浏览器本身可没有具备这样的功能,就需要委托操作系统将消息发送给Web服务器,但是在此之前,我们需要知道域名对应的IP地址,因为委托操作系统发送消息时,这是必须要提供的。
这就需要用到操作系统提供的Socket库,Socket库可以让其他应用程序调用操作系统的网络功能,我们可以调用其中可以解析域名为IP的函数进行处理,那就是gethostbyname()。
以下以Linux下为例。
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
char *ptr="www.houxinlin.com";
struct hostent *hptr;
if ((hptr = gethostbyname(ptr)) == NULL)
{
printf(" 获取失败:%s\n", ptr);
return 0;
}
struct in_addr **addr_list;
int i;
addr_list = (struct in_addr **)hptr->h_addr_list;
for (i = 0; addr_list[i] != NULL; i++)
{
printf("%s \n", inet_ntoa(*addr_list[i]));
}
return 0;
}
上述代码中的hostent是包含主机名、别名、地址类型、地址长度和地址列表的一个结构体。之所以主机的地址是一个列表的形式,原因是当一个主机有多个网络接口时,自然有多个地址。
意义如下。:
h_name – 地址的正式名称。
h_aliases – 空字节-地址的预备名称的指针。
h_addrtype –地址类型; 通常是AF_INET。
h_length – 地址的比特长度。
h_addr_list – 零字节-主机网络地址指针。网络字节顺序。
h_addr - h_addr_list中的第一地址。
三、strace跟踪
我们可以通过strace命令来跟踪一下系统调用,首先什么是strace呢?
strace是一个可用于诊断、调试的Linux用户空间跟踪器。我们可以用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。
下面是执行strace ./a.out
后的部分输出,我们可以看到,客户端与DNS服务器之间传输时用的是UDP,然后sendto向服务器发送要查询的域名,接着recvfrom接收,相应中包含查询到的IP地址。
但其实上面还有一步,会先检查/etc/hosts(对于Linux)文件,如果里面存有对应的信息,就会返回。
四、Socket库
Socket库是在加州大学伯克利分校开发的UNIX系操作系统BSD中开发的C语言库,互联网中所使用的大多数功能都是基于Socket库来开发的。因此,BSD之外的其他操作系统以及C语言之外的其他编程语言也参照Socket库开发了相应的网络库。可以说,Socket 库是网络开发中的一种标准库。