照例是写在前面的话,今天在这里想和自己说一些话,希望未来的自己能够记住,就像我在简书的签名里写下的,“希望自己能记得当下写下那段文字的初心!”,学习其实是一件非常严肃的事情,它容不得半点马虎和粗心,当你在当下去学习的时候,你应该去做的事全心全意,专注的去做当下的这件事,而不是又看电视,有看书,又在玩游戏,因为你看起来在学习,其实是在表演!昨天晚上看了一篇脉脉分享的文章让我感觉到很惭愧,“打工”十年月薪7000,思维落后的努力都是瞎忙,其中有一个观点是,如果你的勤奋只是流于表面,只是为了炫耀与朋友圈,只是为了做给领导看,那你就是假的勤奋,这种表演式的勤奋并不能持续多久。其中一句话是"只有真正的勤奋才能改变一个人的命运,那些假勤奋的人看起来很风光,其实达不到很高的高度!",和大家共勉吧!啰嗦完毕,下面正式开始。
这次写的文章是《网络是怎样连接的》读书笔记,这本书真的是满满的干货,希望每一个程序员都应该学习的一本书,对这本书,真的是相见恨晚。我们这次记录第一章的内容,以后我会坚持把这本书的所有读书笔记都写完。
这张脑图是我自己整理的,还不是很完善,等把所有的章节读完之后,会有一个整体的脑图做出来,那一定很壮观!我们就按照这个脑图上的章节开始整理吧。本笔记中所有的图都来至书中。
我们的探索之旅是从在浏览器中输入一个网址开始的。那么我们就从第一步,网址开始吧!
第一步:解析网址
网址它的另一个名字叫URL
,全名叫:Uniform Resource Locator
,统一资源定位符。还有一个是URI
,全名叫Uniform Resource Identifier
,统一资源标识符。他们两个是什么关系呢?想必很多人都不清楚吧。
URI
叫统一资源表示符,是用字符串标识某一互联网资源,而URL
表示资源的地点(互联网上所处的位置)。可见URL
是URI
的子集。
我们可以看一下URL
的各种格式:
这里我们简单的介绍一下URL
的格式:
1.http
,ftp
,file
,mailto
,news
这部分文字都表示浏览器应 当使用的访问方法:
比如当访问Web 服务器时应该使用HTTPA 协议,而
访问FTP服务器时则应该使用FTP协议。因此,我们可以把这部分理解为
访问时使用的协议类型。尽管后面部分的写法各不相同,但开头部分的
内容决定了后面部分的写法,因此并不会造成混乱。
2.user:password
,表示输入的用户名和密码
3.www.glasscom.com
,表示的访问的域名
4.:80
是表示的端口号
5./dir/file1.html
表示的访问的文件地址。
而在浏览器解析的时候是这样的:
HTTP的基本思路
在解析完网址以后,我们已经知道了想要访问的文件在哪里,这个时候就需要浏览器通过使用HTTP
协议来访问浏览器:
HTTP
协议定义了客户端和服务器之间交互的消息内容和步骤,其基 本思路非常简单。首先,客户端会向服务器发送请求消息。 请求 消息中包含的内容是“对什么”和“进行怎样的操作”两个部分。
其中“对什么”就是URI
,(上面说的那个统一资源定位符)而“进行怎样的操作”就是方法,
方法表示需要让 Web
服务器完成怎样的工作,其中典型的例子包括读取URI表示的数据、 将客户端输入的数据发送给URI
表示的程序等。
那,这里就是大家所熟悉的各种GET,POST,PUT
等方法了,具体方法的含义,我会在另一个笔记中进行详解。
第二步:生成HTTP请求信息
对URL
解析之后,我们知道了Web
服务器和域名,下面就应该生成请求信息了。
我们看一下请求消息的格式:
请求消息:
第一行:请求行,通过这一行可以大致了解请求的内容。
第二行:消息头,每行包含一个头字段,用于表示请求的附加信息。
第三行:消息体,包含客户端向服务端发送的数据。
响应消息:
第一行:状态行
第二行:消息头
第三行:消息体,包含服务器向客户端发送的数据。
这里我们列举一下HTTP
中主要的头字段:
TODO:这里暂时先放在这里,后期在整理到别的专门的一篇里。还有响应消息的状态码,这里也暂时欠缺吧
**注意:1 条请求消息中只能写 1 个 URI。如果需要获取多个文件,必须 对每个文件单独发送 1 条请求。 **
这里是HTTP
消息示例:
第三步:向DNS服务器查询IP地址
说起通过DNS
服务器查询IP
地址,我们需要明白两个概念,一个是IP
,一个是DNS
,
IP地址的基本知识
IP地址的基本思路
在网络中,所有的设备都会被分配一个地址。这个地址就相当于现实 中某条路上的“×× 号 ×× 室”。 其中“号”对应的号码是分配给整个子 网的,而“室”对应的号码是分配给子网中的计算机的,这就是网络中的 地址。“ 号”对应的号码称为网络号,“ 室”对应的号码称为主机号,这个 地址的整体称为IP
地址 。通过IE
地址我们可以判断出访问对象服务器的 位置,从而将消息发送到服务器。消息传送的具体过程在后面的章节有详 细讲解,不过现在我们先简单了解一下。发送者发出的消息首先经过子网
中的集线器 ,转发到距离发送者最近的路由器上。 接下来, 路由器会根据消息的目的地判断下一个路由器的位置,然后将消息发送 到下一个路由器,即消息再次经过子网内的集线器被转发到下一个路由 器。 前面的过程不断重复,最终消息就被传送到了目的地.
实际的IP地址
实际的IP
地址是一串32比特的数字,按照8比特为一组分成4组,分别用十进制表示,然后再用圆点分开。
这就是我们平常经常见到的 IP 地址格式,但仅凭这一 串数字我们无法区分哪部分是网络号,哪部分是主机号。
在 IP 地址的规则 中,网络号和主机号连起来总共是 32 比特,但这两部分的具体结构是不固
定的。在组建网络时,用户可以自行决定它们之间的分配关系,因此,我 们还需要另外的附加信息来表示 IP
地址的内部结构。
这一附加信息称为子网掩码。子网掩码的格式如1.10图所示,是一 串与 IP 地址长度相同的 32 比特数字,其左边一半都是 1,右边一半都是其中,子网掩码为 1 的部分表示网络号,子网掩码为 0 的部分表示主机 号。将子网掩码按照和 IP 地址一样的方式以每 8 比特为单位用圆点分组后 写在 IP 地址的右侧,这就是图 1.9(b)的方法。这种写法太长,我们也可 以把 1 的部分的比特数用十进制表示并写在 IP 地址的右侧,如图 1.9(c) 所示。这两种方式只是写法上的区别,含义是完全一样的。
主机号部分的比特全部为0则表示整个子网
主机号部分的比特全部为1则表示向子网上所有的设备发送包,及“广播”。
关于子网掩码非常不好理解,可以看这里
为什么我们有了域名还会需要IP地址呢?
因为:TCP/IP网络是通过IP地址来确定通信对象的,因此必须知道IP地址。
干嘛不用域名代替IP地址呢?
机器在处理IP的时候要比处理域名要快的多,一个IP地址的长度是32比特,也就是4个字节,而域名最短也要几十个字节,甚至最长255自己。也就是使用IP地址,只需要处理4自己数字。而域名则需要处理几十个到255个自己,这就增加了路由器的负担,传送数据时也会花费更多的时间。
域名是给人用的,这样好记,比如百度,而IP地址是给机器用的,这样快!
应该怎么查IP呢?通过Socket库来查询DNS服务器
这里有几个概念:
什么是解析器?
计算机上负责调用一段程序来查询DNS的客户端叫DNS解析器,简称解析器。
什么是域名解析?
通过DNS查询IP地址的操作称为域名解析。
这一段程序在哪里呢?
在Socket库里,Socket 库是用于调用网络功能的程序组件集合。
解析器的调用
通过Socket库中的代码,调用gethostbyname
,然后输入域名参数,就可以查询到IP地址了
解析器的内部原理
当我们调用Socket
库中的gethostbyname
方法时,我们会生成一条消息,这条消息表示“请告诉我www.baidu.com的ip地址”,并把这条消息通过网卡发送到DNS服务器中进行查询,查询到以后DNS服务器返回响应的消息;从响应的消息中取出IP地址,并存放到内存地址中,接着返回应用程序。
这就是解析器的基本原理。
DNS服务器的基本工作
来自客户端的查询消息包含以下3种信息。
1:域名
服务器、邮件服务器(邮件地址中 @ 后面的部分)的名称
2:Class
在设置DNS方案时,互联网之外的网络也考虑到了,而Class就是用来识别网络的,不过现在只有互联网,所以它的值永远都是代表互联网的IN
3:记录类型
标识域名对应何种类型的记录。
类型为A:表示域名对应的IP地址
类型为MX时,表示域名对应的是邮件服务器。
类型为PTR,表示根据IP地址反查域名。
类型为CNAME,表示查询域名相关别名。
类型为NS,表示查询DNS服务器IP地址。
类型为SOA。表示查询域名属性信息的。
下面是DNS服务器的基本工作;
DNS 服务器会从域名与 IP 地址的对照表中查找相应的记录,并 返回 IP 地址。
域名的层次结构
由于信息实际上并不能全部保存在一台DNS服务器上,而是分布在很多台DNS服务器中,这些DNS服务器相互配合,才能查询出想要的信息。
所以我们这里要看一下:
信息是如何在DNS服务器上注册并保存的。
1.DNS服务器中的所有信息都是按照域名以分层次的结构来保存的。
2.DNS中的域名都是用句点来分割的,比如www.baidu.com
,这个句点就代表了三个层次的域名服务器。www
是一个,baidu
是一个,com
是一个,越靠左层次越高,每个域都是作为一个整体来处理的,也就是一个域就作为一个整体存放在DNS服务器中,上一级域保存着下一级域的信息,也就是www
这个根域保存着baidu
这个域的信息,当我们需要查询的时候,只需要找到根域,然后就可以从根域中查找到我们所要找的域名。
3.实际上域名的根域并不是www
,而是在上一个层次的,这个域名保存着www
这个层次的域名信息。
查找响应的DNS服务器并获取IP地址
我们知道了信息是如何保存的后,也就是知道了应该怎么查询,因为上一级域名保存着下一级域名的信息,上一级的DNS服务器保存着下一级的DNS服务器信息,我们首先访问最近的DNS服务器,这里其实就是我们计算机上自己已经记录的那台DNS服务器,然后我们访问根域的DNS服务器,通过根域我们知道了www
的域名DNS的IP在哪里,然后我们访问它,通过它的信息里保存的信息继续往下查,一直到我们要查的域名为止,接着返回查到的IP地址。
通过上面这两张图我们就知道查询DNS服务器的全貌,大家细细品味一下。
我们还可以更快,通过缓存加快DNS服务器的查询速度
时候并不需要从最上级的根域开始查找,因为 DNS 服务器有一 个缓存 A 功能,可以记住之前查询过的域名。如果要查询的域名和相关信息已 经在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存的位置开 始向下进行。相比每次都从根域找起来说,缓存可以减少查询所需的时间。
第四步:委托协议栈发送消息
既然我们已经知道了IP地址,那么我们就可以委托系统内部的协议栈向这个IP地址也就是Web
服务器发送消息了。
发送消息的过程大体如上图所示的那样:
实际上我们需要经过下面四个步骤:
1.创建套接字(创建套接字阶段)
2.将管道连接到服务器端的套接字上(连接阶段)
3.收发数据(通信阶段)
4.断开管道并删除套接字(断开阶段)
这里我们大体讲一下流程,在第二章节会详细进行讲解
从上面的图中,我们可以分为以下几个步骤:
1.通过解析器查询DNS服务器获取域名的IP地址
2.通过调用socket
组件创建套接字。而描述符就是套接字的句柄,以让客户端加以区分
3.通过调用Socket
库中的connect
方法进行三次握手的连接
4.通过调用Socket
库中的writer
发送数据
5.通过调用Socket
库中的read
接受数据
6.通过调用Socket
库中close
方法断开连接。
关于协议栈发送消息,我们会在第二章部分具体详解。
其实这篇文章是上周就写完的,由于简书的图片不能用外部链接,所在这周才发布!