人人都能看懂的全栈开发教程——网络

人人都能看懂的全栈开发教程——网络

Chris Yue No Comment
Posts

在 Symfony 框架的基础之上我们将项目目前的需求也都实现了,现在可以将代码『部署』到『生产环境』,让因特网里其他的用户也能访问我们的网站。

先说一下在因特网这张大网上,是如何实现网站的访问的。

域名解析

不知道大家有没有换过『DNS 服务』,即使没换过也应该听说过吧,比如著名的谷歌提供的 DNS 服务,8.8.4.4 和 8.8.8.8,大家可以通过各自操作系统的网络设置功能找到可以设置 DNS 服务的地方。DNS 是 Domain Name System 的缩写,从名字可以看出来 DNS 只跟域名(domain)有关。当我们的浏览器开始访问某个页面的时候,第一件事就是把域名发给 DNS 服务,等着 DNS 服务返回域名的 IP。不过这也不是绝对的,如果有的域名以前访问过,你的电脑或者浏览器就会自动记下上一次查询的结果,下一次再访问就直接取结果,节省了查询域名 IP 的时间。

就好像每个有手机的人,都有一两个手机号码一样,链接了互联网的电脑,也会被分配若干个 IP 地址。如果有人知道了你的手机号码,那这个人就可以拨通你的手机;如果有其他接入互联网的电脑知道了你的电脑的 IP,那这些电脑都可以接通你的电脑,两个接通的电脑就可以交换信息了,而网站的访问,就是基于信息的交换。另外需要大家注意的是,信息的交换不要狭隘的想象成只有网站访问,电脑连在一起能做的事情是很多的,不只是网站,其实我们已经看到过非网站方式访问的例子了,比如向 DNS 查询域名 IP。

可能大部分读者还没有自己买过服务器,如果你买了服务器并且被开通的时候,就会占用因特网上的一个 IP 地址,无论你是在哪一家服务商买的服务器,登录管理后台你肯定都能看到服务器的 IP 地址是什么。

而如果你买了域名,你则需要在域名服务商后台,提供域名要绑定的 IP 这个信息,这样其他人就可以通过域名来连接你的电脑而不是靠记 IP 了。

虽然 DNS 查询得非常快,但实际这个过程可没这么简单。DNS 接收到我们的查询请求之后,由于它也会缓存域名信息,如果有缓存直接返回,没有的话它会向『根域名服务』查询,但它并不是查询域名对应的 IP,根域名服务只会返回某个『顶级域名服务』的 IP。举个例子,8.8.8.8 要查询 chrisyue.com 的 IP,发现本地缓存没有,就去问根域名服务器:.com 的顶级域名服务是什么地址;8.8.8.8 得到答案之后,又会去连接 .com 的顶级域名服务,但同样的,也不是直接问 IP 地址,而是问它:chrisyue.com 的域名服务器(不知道中文叫啥,总之英文叫 Name Server)地址是啥,得到答案之后,再连接域名服务器,最终查到 chrisyue.com 的 IP 地址。

在域名管理界面,给域名绑定某个 IP 地址的操作叫做添加 A 记录,以 chrisyue.com 为例,可以通过添加 A 记录的方式,将 chrisyue.com 绑定在某个 IP 上,然后将 www.chrisyue.com 绑定在另外一个 IP 上;当然将它们都绑定在同一个 IP 也是可以的,比如像我这种穷逼没钱买那么多服务器,那我也就只有一个 IP 可以绑,但我依然可以在这一台机器上配置多个域名或者子域名,对应多个站点。

多个域名可以绑定在单个 IP 上,单个域名也可以绑定多个 IP。如果有一天 www.chrisyue.com 访问量暴增服务器快抗不住了,有一种简单粗暴的减压的方式是,再买一台服务器,部署一样的网站;chrisyue.com 再添加一条 A 记录,域名还是 www.chrisyue.com,但 IP 是新加的机器的 IP,等于 www.chrisyue.com 就有两个 IP 记录了,这样不同的 DNS 解析 www 这个域名,就有可能返回老 IP,有可能返回新 IP,让不同的用户连接不同的机器,压力就分散了。

A 记录的域名也可以使用 * 来表示所有的子域名,比如 *.chrisyue.com 或者 *.service.chrisyue.com

除了 A 记录,还能添加 NS 记录,NS 即 Name Server 的简称,即上面 DNS 查询过程中最后一步出现的域名服务器。大家不用担心 NS 服务不知道配置啥,因为基本上所有域名服务商都有自己的 NS,都会有建议提示,甚至直接就帮你配好了。

跟网站访问相关的还有 CNAME 记录。CNAME 记录跟 A 记录有一点类似,都是用来将某个域名绑定某个机器的,只不过 A 记录是绑 IP,而 CNAME 记录是绑另外一个域名。可能有人会觉得有点奇怪,这种像是俄罗斯套娃一样的用法有啥实际用处吗?这种用法用得还挺多的,比如 CDN 服务提供商,就经常要求这么配置。大家先不用了解 CDN 又是个什么玩意儿,可以先举个例子简单理解:chrisyue.com 服务器的带宽不是很多,如果有一个用户访问服务器上某个视频,服务器带宽立马就满了,会影响其他的用户访问网站。为了解决这个问题,我可以把视频或者图片这种比较大的文件复制一份放在另外一个带宽大得多的服务器上,这种服务器虽然只能提供一些静态文件的访问,但这样我原来服务器的带宽就不会受大文件下载的影响了,而且相比我原来的服务器的价格往往也便宜很多,这种服务器就是 CDN 服务商提供的。不过用户因为是去 CDN 服务商的服务器上访问的图片视频,域名肯定也是 CDN 服务商的,可我还是想让域名看起来是我的,毕竟是我自己的东西,这个时候,我就可以使用 CNAME 记录,来将 static.chrisyue.com 域名与 CDN 服务商的服务器域名绑定。虽然,我直接绑定 CDN 服务的 IP 地址也可以,但假如某一天 CDN 服务商说这台机器的 IP 地址会变,那我就得跟着改一次,但如果我绑定的是一个域名,CDN 服务商自己改一下他们的 A 记录就行,压根不用跟我说,我的 CNAME 记录不用做任何变化,另外 CDN 往往也是一个域名分配多个 IP 地址的,还要自己配置这一堆 IP 岂不是太麻烦了。

另外还有 MX (Mail eXchange)记录,TXT 记录等类型,这里就不多说了。

在设置 A 记录时(绑定到 IPv6 是 AAAA 记录,其实都一样),我们还能看到 TTL 这个参数。还记得之前说 DNS 服务会缓存域名记录吗?缓存的时间就是由 TTL 来决定的。比如你设置个 600,那 DNS 服务器就会帮你缓存 600 秒。从上面的 DNS 查询过程来看,一个『完整查询』流程当然更耗时,所以缓存时间越长用户遇到完整查询的可能性越低,但如果设置时间太长,万一哪一天你要换 IP 了,那也得花上很长时间让全网 DNS 都得到更新。

ping 这个命令可能有的小伙伴早就知道了,想要知道某个域名的 IP 是什么,最常用的命令就是 ping 了,而且 ping 这个命令,是少有的 Windows,Mac,Linux 下都有的命令,用法也差不太多:

ping www.chrisyue.com

实际上 ping 这个命令主要用来查看另外一台电脑是否能连接的,如果纯粹只是为了知道域名的 IP,使用 nslookup 命令即可

nslookup www.chrisyue.com

协议

大家多少都在影视作品见过电报这个东西,如果不统一电报的使用方式,有的只用『点』,有的只用『线』,两个电报机就算接通了,双方也不知道对方发的是个啥。网络也一样,机器虽然连通了,但也需要统一使用方式,在计算机的世界叫做『协议』,比较出名的协议有『TCP』和『UDP』,我们访问网站,就是通过『TCP』协议连接的。这里不细说 TCP 的工作方式,大家有兴趣可以自行查询,当然不了解也没关系,并不影响我们开发网站。

两个连通的电报机即使统一了使用方式,比如即使用点也使用线,但如果电报两边点和线的组合指代的含义不同,还是无法将信息传达。对比网络,即使通过 TCP 或者 UDP 建立好了通讯机制,但网络里的信息流如果不统一,还是无法让两台电脑沟通。所以,还需要统一信息流格式。常见的信息流格式就是我们之前已经提过的 ASCII 码。

我们可以通过 tcpdump 命令,来观察网络信息流是如何传递的。

我们先通过 ifconfig 命令,来确定 127.0.0.1 的『网络接口名』是什么。一般来说,ifconfig 返回的结果类似下面的格式:

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
	options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
	inet 127.0.0.1 netmask 0xff000000
	inet6 ::1 prefixlen 128 
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
	nd6 options=201<PERFORMNUD,DAD>

在上面的例子里,能看到第三行出现了 127.0.0.1,那么它的网络接口名就是 lo0,也就是第一行最前面冒号前的字符串。

确认好了网络接口名,我们就可以查看经过指定网络接口的数据流都有什么内容了:

sudo tcpdump -i lo0 -A

sudo 是因为要求 tcpdump 需要权限才能查看,-i lo0 指定了接口(即 interface,即 i)为 lo0-A 指以 ASCII 码方式查看。这个时候我们再用浏览器刷新我们项目的首页,可以看到 tcpdump 会返回一大堆信息。不要被这么多返回吓到了,我们只看熟悉的就行。HTML 和 CSS 代码应该是很明显能看到的,另外还有一些类似这样的内容:

GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:73.0) Gecko/20100101 Firefox/73.0

Cookie: PHPSESSID=9m4u2cimm9qmbkvpfp33bpe2ip

看着 Cookie 那一行应该还熟悉吧,这就是之前聊过的『HTTP 头信息』。

tcpdump 还能加更多的参数做一些筛选工作,比如指定端口,或者指定必须是 TCP 协议。刚才返回结果大部分都是网站,也就是 8000 端口的内容,我们先 Ctrl+C 退出,尝试只看 3306 端口,也就是 MySQL 的端口号,并且限定只能是 TCP 连接:

sudo tcpdump -i lo0 tcp port 3306 -A

tcpdump 依然返回不少东西,不过比之前少多了,虽然内容杂乱无章,但是我们依然能看到 SQL 语句,以及表里面的内容。是的,MySQL 也是基于 TCP + ASCII 来实现的网络传输,跟我们的网站,也就是 HTTP 是一样的!

那是不是我们可以在浏览器里直接访问 MySQL?这个问题读者自己试试就知道,造成这样的原因也很简单,即使传输内容的格式统一了,但不同的应用自己又封装了一层,规定了交流的方式,就好比电报编码都统一了,但电报两边一个只懂英文,一个只懂拼音,这样还是不知道对方在说什么。浏览器和 Web 服务都懂且只懂 HTTP 头信息和正文,他们沟通就没问题,而 MySQL 服务只懂它自己的一种说话方式,你让浏览器跟它硬聊也聊不明白。这种应用自己规定的通讯方式,还是叫『协议』,比如我们已经见过无数遍的『HTTP 协议』;MySQL 也有它自己的协议,而 PDO 无非就是实现了 MySQL 的协议而已。

再跟大家介绍一个有用的命令。有的时候你可能 MySQL 连不上,或者网站访问不了,通过 ping 只能检查机器本身是否连通,而通过 telnet 命令则可以检查端口是否可以访问。我们现在来尝试连接一下 8000 端口:

telnet 127.0.0.1 8000

如果你的 Web 服务是正常运行的,那么上面的命令会返回:

Trying 127.0.0.1…
Connected to localhost.
Escape character is ‘^]’.

那说明 8000 端口已经通了。

我们先不着急退出,我们输入 GET / 后两次回车,我们又看到一堆 HTTP 头信息和 HTML 代码,这是因为刚才输入的代码,实际上已经是最简符合 HTTP 协议的头信息了,服务器能读懂当然能正确的响应。

推荐一个可以通过 telnet 访问的非 HTTP『网站』:

telnet towel.blinkenlights.nl

提示一下:退出 telnet 的方式是先 Ctrl+],再输入 quit 回车。

关于网络部分就先聊到这,下一章我们再接着聊如何部署网站。

人人都能看懂的全栈开发教程——网络 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人

发表评论

5 + 2 =