网络是怎样连接的?从浏览器输入URL开始

1,138 阅读28分钟

介绍

本文将介绍从浏览器输入URL到服务器响应数据,中间到底经历了哪些阶段,本文将带你彻底走进网络的世界,让我们从浏览器出入URL开始,然后一步一步的分析中间的过程。

输入http://www.xxxx.com

探索之旅从输入网址开始

我们现在输入了一个网址,www.xxxx.com, 在介绍浏览器的工作方 式之前,让我们先来介绍一下网址。网址,准确来说应该叫 URL,如果我 说它就是以 http:// 开头的那一串东西,恐怕大家一下子就明白了,但实际 上除了“http:”,网址还可以以其他一些文字开头,例如“ftp:”,“file:”,“mailto:” 等。

这里先说明一下什么是协议:协议就是一种通信规则的定义,比如我们发送了一个使用http协议的数据,那么接收方也必须使用http协议来解析数据,如果不使用http协议就识别不了该数据。

之所以有各种各样的 URL,是因为尽管我们通常是使用浏览器来访问Web 服务器的,但实际上浏览器并不只有这一个功能,它也可以用来在 FTP 服务器上下载和上传文件,同时也具备电子邮件客户端的功能。可以 说,浏览器是一个具备多种客户端功能的综合性客户端软件,因此它需要 一些东西来判断应该使用其中哪种功能来访问相应的数据,而各种不同的 URL 就是用来干这个的,比如访问 Web 服务器时用“http:”,而访问 FTP 服务器时用“ftp:”。

下面举例一些互联网中的一些常见的URL,根据访问目标的不同,URL的写法也会不同

尽管 URL 有各种不同的写法,但它们有一个共同点,那就是 URL 开头的文字,即"http:","ftp:","file:","mailto:"这部分文字都表示浏览器应 当使用的访问方法。比如当访问 Web 服务器时应该使用 HTTP 协议,而访问 FTP 服务器时则应该使用 FTP 协议。因此,我们可以把这部分理解为 访问时使用的协议类型。尽管后面部分的写法各不相同,但开头部分的 内容决定了后面部分的写法,因此并不会造成混乱。

浏览器先要解析 URL

浏览器要做的第一步工作就是对 URL 进行解析,从而生成发送给 Web 服务器的请求消息。刚才我们已经讲过,URL 的格式会随着协议的不同而不同,因此下面我们以访问 Web 服务器的情况为例来进行讲解。

先分析图中a这个url,可以看到url是先有一个http,这个就是url使用的服务器访问协议,浏览器通过分析协议来决定消息的生成方式,然后就是//,后面跟着的是Web服务器名,这个web服务器名就是我们需要访问的域名,再然后就是我们需要访问的数据的路径名,但是路径名是可以省略的。

省略文件名的情况

上图是一个以“http:”开头的典型 URL,但有时候我们也会见到一些不太一样的 URL,例如下面这个 URL 是以“/”来结尾的

我们可以这样理解,以“/”结尾代表 /dir/ 后面本来应该有的文件名被 省略了。根据 URL 的规则,文件名可以像前面这样省略。

不过,没有文件名,服务器怎么知道要访问哪个文件呢?其实,我们 会在服务器上事先设置好文件名省略时要访问的默认文件名。这个设置根 据服务器不同而不同,大多数情况下是 index.html 或者 default.htm 之类的 文件名。因此,像前面这样省略文件名时,服务器就会访问 /dir/index.html 或者 /dir/default.htm。

在解析完URL之后,我们就知道应该要访问的目标在哪里了。接下来,浏览器会使用 http 协议来访问 Web 服务器

生成 HTTP 请求消息

让我们回到对浏览器本身的探索中来,对 URL 进行解析之后,浏览器确定了 Web 服务器和文件名,接下来就是根据这些信息来生成 HTTP 请求消息了。实际上,HTTP 消息在 格式上是有严格规定的,因此浏览器会按照规定的格式来生成请求消息。 ( 看下图 ) 首先,请求消息的第一行称为请求行。这里的重点是最开头的方法,方法可以告诉 Web 服务器它应该进行怎样的操作。不过这里必须先解决一 个问题,那就是方法有很多种,我们必须先判断应该选用其中的哪一种。

解决这个问题的关键在于浏览器的工作状态。这次探索之旅是从在浏 览器顶部的地址栏中输入网址开始的,但浏览器并非只有在这一种场景下 才会向 Web 服务器发送请求消息。比如点击网页中的超级链接,或者在表单中填写信息后点击“提交”按钮,这些场景都会触发浏览器的工作,而 选用哪种方法也是根据场景来确定的

我们的场景是在地址栏中输入网址并显示网页,因此这里应该使用 GET 方法。点击超级链接的场景中也是使用 GET 方法。如果是表单,在 HTML 源代码中会在表单的属性中指定使用哪种方法来发送请求,可能是 GET 也 可能是 POST。

HTTP 中主要的头字段/通用头:适用于请求和响应消息的头字段

头字段类型 含义
Date 表示请求和响应生成的日期
Pragma 表示数据是否允许缓存的通信选项
Cache-Control 控制缓存的相关信息
Connection 设置发送响应之后 TCP 连接是否继续保持的通信选项
Transfer-Encoding 表示消息主体的编码格式
Via 记录途中经过的代理和网关

HTTP 中主要的头字段/请求头:用于表示请求消息的附加信息的头字段

头字段类型 含义
Authorization 身份认证数据
From 请求发送者的邮件地址
If-Modified-Since 如果希望仅当数据在某个日期之后有更新时才执 行请求,可以在这个字段指定希望的日期。一般 来说,这个功能的用途在于判断客户端缓存的数 据是否已经过期,如果已经过期则获取新的数据
Referer 当通过点击超级链接进入下一个页面时,在这里 会记录下上一个页面的 URI
User-Agent 客户端软件的名称和版本号等相关信息
Accept 客户端可支持的数据类型(Content-Type),以 MIME 类型来表示
Accept-Charset 客户端可支持的字符集
Accept-Encoding 客户端可支持的编码格式(Content-Encoding), 一般来说表示数据的压缩格式
Accept-Language 客户端可支持的语言,汉语为 zh,英语为 en
Host 接收请求的服务器 IP 地址和端口号
If-Match 参见 Etag
If-None-Match 参见 Etag
If-Unmodified-Since 当指定日期之后数据未更新时执行请求
Range 当需要只获取部分数据而不是全部数据时,可通 过这个字段指定要获取的数据范围

HTTP 中主要的头字段/响应头:用于表示响应消息的附加信息的头字段

头字段类型 含义
Location 表示信息的准确位置。当请求的 URI 为相对路径 时,这个字段用来返回绝对路径
Server 服务器程序的名称和版本号等相关信息
WWW-Authenticate 当请求的信息存在访问控制时,返回身份认证用 的数据(Challenge)
Accept-Ranges 当希望仅请求部分数据(使用 Range 来指定范围) 时,服务器会告知客户端是否支持这一功能

HTTP 中主要的头字段/响应头:用于表示实体(消息体)的附加信息的头字段

头字段类型 含义
Allow 表示指定的 URI 支持的方法
Content-Encoding 当消息体经过压缩等编码处理时,表示其编码格式
Content-Length 表示消息体的长度
Content-Type 表示消息体的数据类型,以 MIME 规格定义的数 据类型来表示
Expires 表示消息体的有效期
Last-Modified 数据的最后更新日期
Content-Language 表示消息体的语言。汉语为 zh,英语为 en
Content-Location 表示消息体在服务器上的位置(URI)
Content-Range 当仅请求部分数据时,表示消息体包含的数据范围
Etag 在更新操作中,有时候需要基于上一次请求的响应 数据来发送下一次请求。在这种情况下,这个字段 可以用来提供上次响应与下次请求之间的关联信息。 上次响应中,服务器会通过 Etag 向客户端发送一 个唯一标识,在下次请求中客户端可以通过 If- Match、If-None-Match、If-Range 字段将这个标识 告知服务器,这样服务器就知道该请求和上次的响 应是相关的。这个字段的功能和 Cookie 是相同的, 但 Cookie 是网􏱺(Netscape)公司自行开发的规格, 而 Etag 是将其进行标准化后的规格

向 DNS 服务器查询 Web 服务器的 IP 地址

IP 地址的基本知识

生成 HTTP 消息之后,接下来我们需要􏰀托操作系统将消息发送给 Web 服务器。尽管浏览器能够解析网址并生成 HTTP 消息,但它本身并不具备将消息发送到网络中的功能,因此这一功能需要委托操作系统来实现。在进行这一操作时,我们还有一个工作需要完成,那就是查询网址中服务器域名对应的 IP 地址。在委托操作系统发送消息时,必须要提供的不是通信对象的域名,而是它的 IP 地址。因此,在生成 HTTP 消息之后,下 一个步骤就是根据域名查询 IP 地址。在讲解这一操作之前,让我们先来简 单了解一下 IP 地址。

互联网和公司内部的局域网都是基于 TCP/IP 的思路来设计的,所以我 们先来了解 TCP/IP 的基本思路。TCP/IP 的结构如下图所示,就是由一些 小的子网,通过路由器连接起来组成一个大的网络。这里的子网可以理解 为用集线器连接起来的几台计算机,我们将它看作一个单位,称为子网。 将子网通过路由器连接起来,就形成了一个网络。 在网络中,所有的设备都会被分配一个地址。这个地址就相当于现实 中某条路上的“×× 号 ×× 室”。其中“号”对应的号码是分配给整个子 网的,而“室”对应的号码是分配给子网中的计算机的,这就是网络中的 地址。“号”对应的号码称为网络号,“室”对应的号码称为主机号,这个 地址的整体称为 IP 地址。通过 IP 地址我们可以判断出访问对象服务器的 位置,从而将消息发送到服务器。消息传送的具体过程在后面的章节有详 细讲解,不过现在我们先简单了解一下。发送者发出的消息首先经过子网中的集线器,转发到距离发送者最近的路由器上。接下来, 路由器会根据消息的目的地判断下一个路由器的位置,然后将消息发送 到下一个路由器,即消息再次经过子网内的集线器被转发到下一个路由 器(图 1.8 2)。前面的过程不断重复,最终消息就被传送到了目的地。

前面这些就是 TCP/IP 中 IP 地址的基本思路。了解了这些知识之后, 让我们再来看一下实际的 IP 地址。如下图所示,实际的 IP 地址是一串 32 比特的数字,按照 8 比特(1 字节)为一组分成 4 组,分别用十进制表示 然后再用圆点隔开。这就是我们平常经常见到的 IP 地址格式,但仅凭这一 串数字我们无法区分哪部分是网络号,哪部分是主机号。在 IP 地址的规则 中,网络号和主机号连起来总共是 32 比特,但这两部分的具体结构是不固 定的。在组建网络时,用户可以自行决定它们之间的分配关系,因此,我 们还需要另外的附加信息来表示 IP 地址的内部结构。

这一附加信息称为子网掩码。子网掩码的格式如下图所示,是一 串与 IP 地址长度相同的 32 比特数字,其左边一半都是 1,右边一半都是0。其中,子网掩码为 1 的部分表示网络号,子网掩码为 0 的部分表示主机 号。将子网掩码按照和 IP 地址一样的方式以每 8 比特为单位用圆点分组后 写在 IP 地址的右侧,这就是图下图的方法。这种写法太长,我们也可 以把 1 的部分的比特数用十进制表示并写在 IP 地址的右侧,如图下图所示。这两种方式只是写法上的区别,含义是完全一样的。

域名和 IP 地址并用的理由

TCP/IP是通过IP地址来确定通信对象的,因此不知道IP地址就无法将消息发送给对方,这和我们打电话的时候必须要知道对方的电话号 码是一个道理。因此,在委托操作系统发送消息时,必须要先查询好对方 的IP地址。

可能你会问“既然如此,那么在网址中不写服务器的名字,直接写 IP 地址不就好了吗?”实际上,如果用 IP 地址来代替服务器名称也是能够正常工作的。然而,就像你很难记住电话号码一样,要记住一串由数字组成 的 IP 地址也非常困难。因此,相比 IP 地址来说,网址中还是使用服务器名称比较好。

那么又有人问了:“既然如此,那干脆不要用 IP 地址,而是用名称来确定 通信对象不就好了吗?互联网中使用的是最新的网络技术,和电话那种老古 董可不一样,这样的功能应该还是做得到的吧?”这样的想法其实并不奇怪 。不过从运行效率上来看,这并不能算是一个好主意。互联网中存在无数的路由器,它们之间相互配合,根据 IP 地址来判断应该把数据传送到什么地方。那么如果我们不用 IP 地址而是改用名称会怎么样呢? IP 地址的长度 为 32 比特,也就是 4 字节,相对地,域名最短也要几十个字节,最长甚至 可以达到 255 字节。换句话说,使用 IP 地址只需要处理 4 字节的数字,而 域名则需要处理几十个到 255 个字节的字符,这增加了路由器的负担,传送 数据也会花费更长的时间 D。可能有人会说:“那使用高性能路由器不就能解 决这个问题了吗?”然而,路由器的速度是有极限的,而互联网内部流动的 数据量已然让路由器疲于应付了,因此我们不应该再采用效率更低的设计。 随着技术的发展,路由器的性能也会不断提升,但与此同时,数据量也在以更快的速度增长,在可预见的未来,这样的趋势应该不会发生变化。出于这样的原因,使用名称本身来确定通信对象并不是一个聪明的设计。

于是,现在我们使用的方案是让人来使用名称,让路由器来使用 IP 地 址。为了填补两者之间的障碍,需要有一个机制能够通过名称来查询 IP 地 址,或者通过 IP 地址来查询名称,这样就能够在人和机器双方都不做出牺牲的前提下完美地解决问题。这个机制就是 DNS。

Socket 库提供查询 IP 地址的功能

查询 IP 地址的方法非常简单,只要询问最近的 DNS 服务器“www. lab.glasscom.com 的 IP 地址是什么”就可以了,DNS 服务器会回答说“该 服务器的 IP 地址为 xxx.xxx.xxx.xxx”。这一步非常简单,很多读者也都很 熟悉,那么浏览器是如何向 DNS 服务器发出查询的呢?让我们把向 Web 服务器发送请求消息的事情放一放,先来探索一下 DNS。

向 DNS 服务器发出查询,也就是向 DNS 服务器发送查询消息,并接收服务器返回的响应消息。换句话说,对于 DNS 服务器,我们的计算机上 一定有相应的 DNS 客户端,而相当于 DNS 客户端的部分称为 DNS 解析器,或者简称解析器。通过 DNS 查询 IP 地址的操作称为域名解析,因此负责执行解析(resolution)这一操作的就叫解析器(resolver)了。

解析器实际上是一段程序,它包含在操作系统的 Socket 库中,在介绍解析器之前,我们先来简单了解一下 Socket 库。首先,库到底是什么东西 呢?库就是一堆通用程序组件的集合,其他的应用程序都需要使用其中的 组件。库有很多好处。首先,使用现成的组件搭建应用程序可以节省编程 工作量;其次,多个程序使用相同的组件可以实现程序的标准化。除此之 外还有很多其他的好处,因此使用库来进行软件开发的思路已经非常普及, 库的种类和数量也非常之多。Socket 库也是一种库,其中包含的程序组件可以让其他的应用程序调用操作系统的网络功能,而解析器就是这个库中的其中一种程序组件。

通过解析器向 DNS 服务器发出查询

解析器的用法非常简单。Socket 库中的程序都是标准组件,只要从应用 程序中进行调用就可以了。具体来说,在编写浏览器等应用程序的时候,只要像下图这样写上解析器的程序名称“gethostbyname”以及 Web 服务器的域名“www.lab.glasscom.com” 就可以了,这样就完成了对解析器的调用 。

调用解析器后,解析器会向 DNS 服务器发送查询消息,然后 DNS 服务器会返回响应消息。响应消息中包含查询到的 IP 地址,解析器会取出 IP 地址,并将其写入浏览器指定的内存地址中。只要运行上图中的这一行程序,就可以完成前面所有这些工作,我们也就完成了 IP 地址的查询。接 下来,浏览器在向 Web 服务器发送消息时,只要从该内存地址取出 IP 地 址,并将它与 HTTP 请求消息一起交给操作系统就可以了。

顺带一提,向 DNS 服务器发送消息时,我们当然也需要知道 DNS 服 务器的 IP 地址。只不过这个 IP 地址是作为 TCP/IP 的一个设置项目事先设 置好的,不需要再去查询了。不同的操作系统中 TCP/IP 的设置方法也有差 异,Windows 中的设置如下图所示,解析器会根据这里设置的 DNS 服 务器 IP 地址来发送消息。

全世界 DNS 服务器的大接力

DNS 服务器的基本工作

前文介绍了解析器与 DNS 服务器之间的交互过程,下面来了解一下 DNS 服务器的工作。DNS 服务器的基本工作就是接收来自客户端的查询消息,然后根据消息的内容返回响应。

其中,来自客户端的查询消息包含以下 3 种信息。

  1. 域名 服务器、邮件服务器(邮件地址中 @ 后面的部分)的名称

  2. Class 在最早设计 DNS 方案时,DNS 在互联网以外的其他网络中的应用,也被考虑到了,而 Class 就是用来识别网络的信息。不过,如今除了互联网并没有其他的网络了,因此 Class 的值永远是代表互联网的 IN

  3. 记录类型 表示域名对应何种类型的记录。例如,当类型为 A 时,表示域名 对应的是 IP 地址;当类型为 MX 时,表示域名对应的是邮件服务器。对于不同的记录类型,服务器向客户端返回的信息也会不同

DNS 服务器上事先保存有前面这 3 种信息对应的记录数据,如下图所示。DNS 服务器就是根据这些记录查找符合查询请求的内容并对客户端 作出响应的。

例如,如果要查询 www.lab.glasscom.com 这个域名对应的 IP 地址,客 户端会向 DNS 服务器发送包含以下信息的查询消息。

  1. 域名 = www.lab.glasscom.com
  2. Class = IN
  3. 记录类型=A

然后,DNS 服务器会从已有的记录中查找域名、Class 和记录类型全部匹配的记录。假如 DNS 服务器中的记录如上图所示,那么第一行记录与查询消息中的 3 个项目完全一致。于是,DNS 服务器会将记录中的 192.0.2.226 这个值返回给客户端。然而,Web 服务器的域名有很多都是像 www.lab.glasscom.com 这样以 www 开头的,但这并不是一定之规,只是因为 最早设计 Web 的时候,很多 Web 服务器都采用了 www 这样的命名,后来就 形成了一个惯例而已。因此,无论是WebServer1 也好,MySrv 也好,只要是 作为 AA 记录在 DNS 服务器上注册的,都可以作为 Web 服务器的域名。

在查询 IP 地址时我们使用 A 这个记录类型,而查询邮件服务器时则 要使用 MXC 类型。这是因为在 DNS 服务器上,IP 地址是保存在 A 记录中 的,而邮件服务器则是保存在 MX 记录中的。例如,对于一个邮件地址 tone@glasscom.com,当需要知道这个地址对应的邮件服务器时,我们需要提供 @ 后面的那一串名称。查询消息的内容如下。

  1. 域名 = glasscom.com
  2. Class = IN
  3. 记录类型 = MX

DNS 服务器会返回 10 和 mail.glasscom.com 这两条信息。当记录类型 为 MX 时,DNS 服务器会在记录中保存两种信息,分别是邮件服务器的域名和优先级。此外,MX 记录的返回消息还包括邮件服务器 mail.glasscom. com 的 IP 地址。上表的第三行就是 mail.glasscom.com 的 IP 地址,因此只要用 mail.glasscom.com 的域名就可以找到这条记录。

综上所述,DNS 服务器的基本工作就是根据需要查询的域名和记录类型查找相关的记录,并向客户端返回响应消息。

域名的层次结构

在前面的讲解中,我们假设要查询的信息已经保存在 DNS 服务器内部 的记录中了。如果是在像公司内部网络这样 Web 和邮件服务器数量有限的 环境中,所有的信息都可以保存在一台 DNS 服务器中,其工作方式也就完 全符合我们前面讲解的内容。然而,互联网中存在着不计其数的服务器,将这些服务器的信息全部保存在一台 DNS 服务器中是不可能的,因此一定 会出现在 DNS 服务器中找不到要查询的信息的情况。下面来看一看此时 DNS 服务器是如何工作的。

直接说答案的话很简单,就是将信息分布保存在多台 DNS 服务器中, 这些 DNS 服务器相互接力配合,从而查找出要查询的信息。不过,这个机 制其实有点复杂,因此我们先来看一看信息是如何在 DNS 服务器上注册并保存的。

首先,DNS 服务器中的所有信息都是按照域名以分层次的结构来保存 的。层次结构这个词听起来可能有点不容易懂,其实就类似于公司中的事业集团、部门、科室这样的结构。层次结构能够帮助我们更好地管理大量的信息。

DNS 中的域名都是用句点来分隔的,比如 www.lab.glasscom.com,这 里的句点代表了不同层次之间的界限,就相当于公司里面的组织结构不用 部、科之类的名称来划分,只是用句点来分隔而已。在域名中,越靠右的 位置表示其层级越高,比如 www.lab.glasscom.com 这个域名如果按照公司 里的组织结构来说,大概就是“com 事业集团 glasscom 部 lab 科的 www” 这样。其中,相当于一个层级的部分称为域。因此,com 域的下一层是 glasscom 域,再下一层是 lab 域,再下面才是 www 这个名字。

寻找相应的 DNS 服务器并获取 IP 地址

下面再来看一看如何找到 DNS 服务器中存放的信息。这里的关键在于 如何找到我们要访问的 Web 服务器的信息归哪一台 DNS 服务器管。

互联网中有数万台 DNS 服务器,肯定不能一台一台挨个去找。我们可 以采用下面的办法。首先,将负责管理下级域的 DNS 服务器的 IP 地址注 册到它们的上级 DNS 服务器中,然后上级 DNS 服务器的 IP 地址再注册到 更上一级的 DNS 服务器中,以此类推。也就是说,负责管理 lab.glasscom.com 这个域的 DNS 服务器的 IP 地址需要注册到 glasscom.com 域的 DNS 服务器中,而 glasscom.com 域的 DNS 服务器的 IP 地址又需要注册到 com 域的 DNS 服务器中。这样,我们就可以通过上级 DNS 服务器查询出下级 DNS 服务器的 IP 地址,也就可以向下级 DNS 服务器发送查询请求了。

在前面的讲解中,似乎 com、jp 这些域(称为顶级域)就是最顶层了, 它们各自负责保存下级 DNS 服务器的信息,但实际上并非如此。在互联网 中,com 和 jp 的上面还有一级域,称为根域。根域不像 com、jp 那样有自 己的名字,因此在一般书写域名时经常被省略,如果要明确表示根域,应该像 www.lab.glasscom.com. 这样在域名的最后再加上一个句点,而这个最 后的句点就代表根域。不过,一般都不写最后那个句点,因此根域的存在 往往被忽略,但根域毕竟是真实存在的,根域的 DNS 服务器中保管着 com、jp 等的 DNS 服务器的信息。由于上级 DNS 服务器保管着所有下级 DNS 服务器的信息,所以我们可以从根域开始一路往下顺藤摸瓜找到任意 一个域的 DNS 服务器。

除此之外还需要完成另一项工作,那就是将根域的 DNS 服务器信息保 存在互联网中所有的 DNS 服务器中。这样一来,任何 DNS 服务器就都可 以找到并访问根域 DNS 服务器了。因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再一路顺藤摸瓜 找到位于下层的某台目标 DNS 服务器(如下图)。分配给根域 DNS 服务器 的 IP 地址在全世界仅有 13 个 A,而且这些地址几乎不发生变化,因此将这 些地址保存在所有的 DNS 服务器中也并不是一件难事。实际上,根域 DNS 服务器的相关信息已经包含在 DNS 服务器程序的配置文件中了,因 此只要安装了 DNS 服务器程序,这些信息也就被自动配置好了。

收到客户端的查询消息之后,DNS 服务器会按照前面的方法来查询 IP 地址,并返回给客户端。这样,客户端就知道了 Web 服务器 的 IP 地址,也就能够对其进行访问了。

委托协议栈发送消息

数据收发操作概览

知道了 IP 地址之后,就可以􏰀托操作系统内部的协议栈向这个目标 IP 地址,也就是我们要访问的 Web 服务器发送消息了。要发送给 Web 服务 器的HTTP消息是一种数字信息(digital data),因此也可以说是􏰀托协议 栈来发送数字信息。收发数字信息这一操作不仅限于浏览器,对于各种使 用网络的应用程序来说都是共通的。因此,这一操作的过程也不仅适用于 Web,而是适用于任何网络应用程序。下面就来一起探索这一操作的过程。

和向 DNS 服务器查询 IP 地址的操作一样,这里也需要使用 Socket 库中 的程序组件。不过,查询 IP 地址只需要调用一个程序组件就可以了,而这 里需要按照指定的顺序调用多个程序组件,这个过程有点复杂。发送数据是 一系列操作相结合来实现的,如果不能理解这个操作的全貌,就无法理解其 中每个操作的意义。因此,我们先来介绍一下收发数据操作的整体思路。

使用 Socket 库来收发数据的操作过程如下图所示。简单来说,收发数据的两台计算机之间连接了一条数据通道,数据沿着这条通道流动,最终到达目的地。我们可以把数据通道想象成一条管道,将数据从一端送入 管道,数据就会到达管道的另一端然后被取出。数据可以从任何一端被送入管道,数据的流动是双向的。不过,这并不是说现实中真的有这么一条管道,只是为了帮助大家理解数据收发操作的全貌。

收发数据的整体思路就是这样,但还有一点也非常重要。光从图上来 看,这条管道好像一开始就有,实际上并不是这样,在进行收发数据操作 之前,双方需要先建立起这条管道才行。建立管道的关键在于管道两端的 数据出入口,这些出入口称为套接字。我们需要先创建套接字,然后再将 套接字连接起来形成管道。实际的过程是下面这样的。首先,服务器一方 先创建套接字,然后等待客户端向该套接字连接管道。当服务器进入等待状态时,客户端就可以连接管道了。具体来说,客户端也会先创建一个套 接字,然后从该套接字延伸出管道,最后管道连接到服务器端的套接字上。 当双方的套接字连接起来之后,通信准备就完成了。接下来,就像我们刚 刚讲过的一样,只要将数据送入套接字就可以收发数据了。