0


网络原理之HTTP/HTTPS、TCP、IP四层协议栈

文章目录

一、应用层

  应用层协议包括请求报文和响应报文,一般应用层协议都是由开发这个软件的程序猿来约定的,设计一个应用层协议,主要包含两个工作

  1. 明确传输的信息
  2. 明确数据的组织格式**  由于应用层协议可以随心所欲的设计,这就导致公司设计的协议两极分化很严重,好的很好,差的很糟糕。因此,大佬们发明了一些比较好的协议模板,我们可以直接往上套**

(一)xml协议

  xml是用的比较久的数据格式,现在虽然也在用,但是用的越来越少,xml的格式非常有特点,由标签构成

格式:

<标签名>内容</标签名>

<标签名>,是开始标签
内容就是要表示的值
</标签名>,是结束标签

  优点很明显,通过这些标签,就更好的体现了数据的可读性,尤其是哪个部分是啥意思,一目了然。但是缺点也很明显,虽然

xml

提高了可读性,但是又引入了太多的辅助信息,就导致传输相同数据的请求时,占用的网络带宽更高,而如果带宽固定,相同时间能传输的请求个数就是更少,值得一提的是,带宽很贵
**  综上所述,正是因为上面的优点和缺点,

xml

现在很少作为应用层协议的设计模板,现在使用

xml

主要是作为一些配置文件**

(二)json协议

  当下最流行的设计应用层协议的数据格式就是

json

json

的格式比也很有特点,是键值对的格式
格式:

{
    键:值,
    键:值,
    ...
    键:值
}

  通过

{}

构成了键值对结构,一个

{}

中有很多个键值对,键值对之间用 逗号 分割,键和值之间用 冒号 分割,要求键必须是字符串类型,值允许很多种(数字,字符串,布尔,数组,甚至是另一个json…),**

json

中表示字符串,单双引号都可以,而又由于

json

要求

key

必须是字符串,因此

key

这里的引号可以省略,除非

key

中包含了一些特殊符号(空格,-…),则必须加上引号**
  可以看出,

json

的传输效率比

xml

高,但仍然要多传递一些冗余信息,就是

key

的名字,这一点在表示数组时尤为明显,一个数组中的key将会重复很多份

(三)protobuffer协议

  因此

protobuffer

应运而生,比

json

更加精简,是一种二进制格式的数据,在

protobuffer

的数据中,**不再包含

key

的名字,而是通过顺序以及一些特殊字符,来区分每个字段的含义,同时再通过一个 IDL 文件,来描述这个数据格式(说明每个部分是啥意思), IDL 只是起到一个辅助开发的效果,并不会真正的传输,传输的只是二进制的纯粹的数据**
比如数据格式就是这种:

中国\北京\朝阳区\身份证号

  通过二进制的数据重新对这里的内容进行编排甚至压缩,这样做之后传输效率更高,但是这个数据难以观察,调试起来不方便

  开发效率包含开发和调试,如果线上环境出问题了,如果用json,出问题的请求和响应一目了然;如果是用protobuffer,二进制的数据我们无法直接通过肉眼观察,就得自己开发一个专门的程序来解析这个数据,分析问题,而开发效率 > 运行效率
  设计应用层协议,是一件非常普遍的事情,设计应用层协议,要做的工作:

  1. 明确传输的信息(根据需求)
  2. 明确传输的格式(参考现有模板)

除此之外,业界也有一些现成的,已经被设计好,被广泛使用了的应用层协议,我们稍加修改,就可以使用,最知名的就是HTTP协议

(四)HTTP协议

**  HTTP (全称为 “超文本传输协议”) 是一种应用非常广泛的应用层协议**
HTTP协议的重要性

  1. HTTP 协议大概率是我们日后开发中用的最多的协议
  2. HTTP 处于 TCP / IP 五层协议栈中的应用层
  3. HTTP 是设计好的协议,但是自身的可扩展性很强,可以根据自身需要,去传输各种自定义的数据信息

  HTTP/1和HTTP/2在传输层是基于TCP的,而HTTP/3是基于UDP的,而现在主流的还是HTTP1.1版本的,由于HTTP是一个文本格式的协议,我们可以不需要理解具体的二进制位,而只需要理解文本的格式,我们可以通过抓包工具来看它的报文结构

1. 抓包工具,fiddler

**  抓包工具,其实就是一个第三方程序,而fiddler就是一个专门抓HTTP的抓包工具,我们可以直接在官网下载。在这个网络通信的过程中,类似于“代理”,如下图所示:**
抓包工具的作用

Fiddler 使用方式:

  1. 打开 Fiddler,然后打开你要访问的网站,访问该网站的 HTTP 请求和响应就会显示在 Fiddler 上> fiddler左侧列表,显示当前抓到的所有HTTP/HTTPS的数据报> fiddler左侧内容
  2. 当我们选择好我们具体要查看的 HTTP/HTTPS 请求和响应时,双击左边栏具体的报文,右上栏就会显示具体的请求报文内容,右下角就会显示具体的响应报文内容(需要点击 Raw 标签来查看详细的数据格式)> fiddler请求和响应> 标签页的选项,就表示当前使用啥样的格式来显示HTTP请求,我们用的最多的就是row选项(原始的),这样我们看到的就是HTTP请求数据的本体> 标签页
  3. 如果觉得直接在fiddler看的累,我们可以通过右下角的 view in Notepad 键通过记事本打开请求或响应,通过记事本来看> fiddler请求
  4. 响应的正文往往是被显示在浏览器上,最常见的响应格式就是 html,很多网站返回的 html 是压缩过的(因为压缩之后,网络传输的数据量就变少了,即节省了网络带宽),此时在我们看来就是一段乱码,所以需要进行解压缩 decode
  5. 为了方便我们抓取我们自己想查看的抓包结果,可以通过 ctrl + a 全选左侧的抓包结果,delect 删除选中的所有抓包结果,再进行网页的刷新就行

注意: 直接安装的 Fiddler 是无法查看 HTTPS 的请求的,需要进行下面的配置才能查看HTTPS的包:
fiddler的配置

2. HTTP报文格式

HTTP请求和响应的报文格式并不相同
HTTP请求响应报文格式
和具体报文对照着看
请求报文
HTTP请求举例
请求分为四个部分:

  1. 请求行: a)HTTP 的方法,描述请求想干啥。GET 就是想从服务器获取到某个东西。 b)URL,描述了要访问得到网络上的资源具体在哪儿。 c)版本号,HTTP/1.1 表示当前使用的 HTTP 版本号是 1.1。1.1 是当下最主流的版本。
  2. 请求头,包含了很多行: a)每一行都是一个键值对,键和值之间使用:空格来分割 b)键值对的个数是不确定的,不同的键值对,表示的含义是不一样的
  3. 空行:相当于请求的结束标志
  4. 请求正文(body):可选的,有的有,有的没有。空行后面的就是正文

响应报文
HTTP响应举例
响应也是分为四个部分:

  1. 首行:包含了 3 个部分: a)版本号:HTTP/1.1 b)200:状态码,描述了这个响应,是一个表示 ”成功“ 还是 ”失败“ ,以及其他不同的状态码,描述了失败的原因。 c)200:状态码描述,通过 一个/一组 简单的单词,来描述当前的状态码的含义
  2. 响应头:也是键值对结构,每个键值对占一行,每个键值对之间使用 : 和 空格 来分割。响应头当中的键值对个数,也是不确定的,不同的键值对表示不同的含义
  3. 空行:表示响应头的结束
  4. 响应正文:就是服务器返回给客户端的具体数据。内容可能有各种格式,最常见的就是 HTML

3. HTTP请求(Request)

(1)URL基本格式

**  URL的含义就是“网络上唯一资源的地址符”,既要明确主机是谁,又要明确主机上的哪个资源,而URL都要遵守一个基本模板:**
HTTP URL结构

  1. 协议方案名,就是描述了这个 URL 是给哪个协议来使用的
  2. 登录信息,现在不用了,以前会用
  3. 服务器地址,就是当前要访问的主机是啥,可以是IP地址,也可以是域名
  4. 端口号,就是表示当前要访问的主机上的哪个应用程序。大部分情况下,端口号都是会省略的。省略的时候,浏览器会自动加一个端口号
  5. 文件路径,描述了当前要访问的服务器资源是啥

通过这些IP地址,端口,带层次的文件路径,就描述了一个网络上具体的资源

  1. 查询字符串,本质上是 浏览器/客户端 由程序猿定义,给服务器传送的自定义信息,相当于对获取到的资源提出了进一步的要求,本质上也是键值对结构,文件路径和查询字符串之间用“?”分割,查询字符串中的每个键值对之间用“&”分割
  2. 片段标识符,描述了要访问当前 HTML 页面中哪个具体的子部分,能够控制浏览器滚动到相关的位置

小结:对于URL来说,虽然里面的结构很复杂,但是最重要的,与开发最紧密的,主要就是四个部分:(1)ip地址/域名,(2)端口号(经常省略),(3)带层次结构的路径,(4)query String 查询字符串

URL 的 encode/decode
  当 query string 中如果包含了特殊字符,就需要对特殊字符进行转义。转义的过程就叫做 URLencode,反之,把转义后的内容还原回来,就叫做URLdecode。

  因为一个 URL 里面是有很多特殊的含义的符号的:/  :  ?   &   = +…这些符号都是在 URL中具有特定含义的。万一,queryString 里面也包含这类特殊符号,就可能导致 URL 被解析失败!所以要进行 encode

(2)URL方法

方法说明适用版本号GET获取资源HTTP 1.0、HTTP 1.1POST传输实体主体HTTP 1.0、HTTP 1.1PUT传输文件HTTP 1.0、HTTP 1.1HEAD获得报文首部HTTP 1.0、HTTP 1.1DELETE删除文件HTTP 1.0、HTTP 1.1OPTIONS访问支持的方法HTTP 1.1TRACE追踪路径HTTP 1.1CONNECT要求用隧道协议连接代理HTTP 1.1LINK建立和资源之间的联系HTTP 1.1UNLINE断开连接关系HTTP 1.1
**上述方法只罗列到1.1,后续的2,3版本并不考虑,而其中最最常用的就是

GET

POST

方法**

浏览器发送GET请求的情况

  1. 直接在地址栏里输入URL
  2. 通过a标签跳转
  3. 通过img/link/script…
  4. 通过 form 表单,method指定为GET
  5. 通过 ajax ,type指定为GET

浏览器发送POST请求的情况

  1. 通过 form 表单,method 指定为 POST
  2. 通过 ajax,type指定为POST

GET 和 POST 的区别:

GET 和 POST 没有本质区别。具体来说,相当于是 GET 使用的场景,也能换成 POST。POST 使用的场景,也能换成 GET。但是细节上还是有区别的:

  1. GET 通常用来取数据。POST 通常用来上传数据。
  2. 通常情况下,GET 没有 body,GET 是通过 query string 向服务器传递数据的。通常情况下,POST 是有 body 的,通过 body 向服务器传递数据。
  3. GET 请求一般是幂等(每次相同的输入,得到的输出结果是确定的)的,POST 请求一般是不幂等(每次相同的输入,得到的结果是不确定的)的。
  4. GET 可以被缓存,POST 不能被缓存(承接第三点,幂等才可以缓存,如果不幂等,就没有缓存的必要,毕竟结果不确定,需要实时计算)。
关于 GET 请求的 URL 长度问题的误解
  • 网上有一种错误的解释: GET 请求的长度是存在上限的,这个上限有被说成 1024kb、2048kb 等等,并且 GET 请求存在上限的原因是 URL 的长度存在上限
  • RFC 2616 标准正确的解释: HTTP 协议由 RFC 2616 标准定义,该标准中明确说明 “Hypertext Transfer Protocol – HTTP/1.1,” does not specify any requirement for URL length,即没有对 URL 的长度有任何限制
  • URL 的长度取决因素: 实际上 URL 的长度取决于浏览器的实现和 HTTP 服务器端的实现。在浏览器端,不同的浏览器最大的长度是不同的,但是现在浏览器支持的长度一般都很长;在服务器端,一般这个长度是可以配置的
关于 POST 比 GET 更安全的误解
  • 网上有一种错误的解释: 如果实现登录页面,如果使用 GET 实现登录,GET 习惯上把数据放到 query string 中,此时就能看到浏览器的 URL 中显示当前的用户名和密码了,所以就并不安全;而 POST 习惯上会把数据放到 body 中,因此登录时就不能直接看到用户名和密码,就安全
  • 正确的理解: 安全问题取决于是否加密以及加密算法的强度。这和将数据信息放到 query string 或 body 中无关,因为通过抓包,我们就可以得到这两部分的数据,只要是明文传输,都是不安全的
关于 GET 只能传输文本数据的误解
  • 网上有一种错误的解释: GET 只能传输文本数据;POST 可以传输文本数据,也可以传输二进制数据
  • 正确的理解: GET 也可以传输二进制数据,虽然不能直接在 query string 中传输二进制数据,但是可以针对二进制数据进行 urlencode,转码后就可以放到 url 中;GET 还可以直接将二进制数据放到 body 中

(3)请求报头(header)

header 的整体格式是键值对结构,每个键值对占一行,键和值之间使用

冒号+空格

进行分割

Host

表示服务器主机的地址和端口

ConTent-Length

表示 body 的数据长度,长度单位是字节
  关于 ConTent-length,HTTP 也是基于 TCP 协议的,TCP 是面向字节流,有粘包问题,所以这里也有,就可以通过下面这两种方法来解决:

  • 使用分隔符(如果是GET请求,由于GET没有body,但有空行,因此可以直接通过空行分割)
  • 使用长度(如果是使用POST,空行后面还有body,当应用程序读到空行时,就可以根据ConTent-Length写明的长度,继续读取若干长度的数据,避免粘包问题)
ConTent-Type

表示 body数据格式,介绍三种请求中的数据格式

  • application/x-www-form-urlencoded> 这是 form 表单提交的数据格式,此时 body 的格式就类似于 query string(是键值对的结构,键值对之间使用 & 分割,键与值之间使用 = 分割
  • multipart/form-data> 这是 form 表单提交的数据格式(需要在 from 标签上加上 enctyped=“multipart/form-data”),通常用于 HTML 提交图片或者文件
  • application/json> 此时 body 数据为 json 格式,json 格式就是源自 js 的对象的格式。用一个 { } 括住,里面有多个键值对,键值对之间使用逗号分割,键和值之间使用冒号分割
User-Agent(简称UA)

这里表示的是,当前用户是拿一个什么样的东西来上网,比如:
User-Agent
现在 User-Agent 的作用,更多的是用来区别电脑和手机,毕竟屏幕尺寸不同

Referer

表示当前的页面,是从哪个页面跳过来的
Referer
表示当前页面是从搜狗转过来的。Referer 的一个作用就是,可以看到广告的点击跳转从哪里来的,广告主就可以通过Referer来区分是哪个广告平台导入过来的

Cookie

Cookie 是什么?
  Cookie 是浏览器给页面提供的一种纽扣持久化存储数据的机制,把一些信息写在特定的文件里面。最典型的应用场景就是存储当前用户的身份信息,就像我们登录 CSDN 之后,刷新页面,或者重新打开 CSDN 网站,仍然是已登录状态

为什么需要 Cookie?
  如果没有 Cookie,直接将要存储的数据保存在客户端浏览器所在的主机的硬盘上,那么就会出现很大的安全风险,比如当你不小心打开某个不安全的网站,该网站就可以在你的硬盘上写一个病毒程序,那么你的电脑就挂了!因此浏览器为了保证安全性,就禁止网页中的代码访问主机的硬盘(无法在 JS 中读写文件),因此也就失去了持久化存储的能力,故 Cookie 就很重要!

具体的组织形式

  1. 先按照域名来组织。针对每个域名,分配一个小房间。
  2. 然后在小房间里面,又会根据 键值对 来组织数据

Cookie 来自哪里,如何往 Cookie 中存储数据?
  Cookie 这个数据可能是客户端(网页)自行通过 JS 写入的,也可能来自于服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段给浏览器返回数据。

  Cookie 在浏览器这边是按照域名维度来存储的,例如我们打开 CSDN 的首页,点击网址栏左边的一把小锁就能找到 Cookie,我们就可以看到打开这个网页时,系统按照不同域名设置了 Cookie
Cookie

Session
  就是会话,就像微信消息列表,就相当于是会话列表。聊天记录,就相当于是用户的详细信息,是储存在服务器上的,Cookie传过来一个会话id,服务器通过会话id找到用户对应的会话,进一步获取到用户的详细情况

4. HTTP响应(Response)

(1)状态码

  状态码表示访问一个页面的结果(如访问成功、失败,还是其它一些情况等等),它是一个3位的整数,从 1xx、2xx(成功)、3xx(重定向)、4xx(客户端错误)、5xx(服务器错误),分为五个大类,每个大类的含义都不同。以下介绍一些常见的状态码及它的状态码解释

  1. 200 OK 表示访问成功
  2. 404 Not Found 表示没有找到资源
  3. 403 Forbidden 表示访问被拒绝 > 有的页面通常需要用户有一定的权限才能访问,如未登录
  4. 405 Method Not Allowed 表示访问的服务器不能支持请求中的方法或者不能使用该请求中的方法
  5. 500 Internal Server Error 表示服务器出现内部错误 > 一般是服务器的代码执行过程中遇到了一些特殊的情况,造成服务器崩溃可能会产生这个状态码
  6. 504 Gateway Timeout 表示当前服务器负载比较大,服务器处理单条请求的时耗很长,就会出现超时情况
  7. 302 Move temporarily 表示临时重定向,和Location配合使用,描述接下来要跳转到哪里,一般登录时会遇到这个状态 > 重定向相当于手机呼号的呼叫转移功能,如果我们换了一个手机号,就可以去办理该呼叫转移业务,使朋友拨打你的旧号码时,自动跳转到新号码
  8. 301 Moved Permanently 表示永久重定向,当浏览器收到这种响应时,后续的请求都会被自动改成新的地址
  9. 418 彩蛋 描述:I am a teapot,我是一个茶壶,来自程序猿的幽默

(2)认识响应“报头”(header)

  响应报头的基本格式和请求报头的格式基本一致,下面介绍下响应报头的 Content-Type 参数
Content-Type
  Content-Type 表示 body 的数据格式,以下介绍三种响应中的数据格式

  • text/html> 表示数据格式是 HTML
  • text/css> 表示数据格式是 CSS
  • application/javascript> 表示数据格式是 JavaScript
  • application/json> 表示数据格式是 JSON

4. 通过 form 表单构造 HTTP 请求

  form 是 HTML 中的一个表单标签,可以用于给服务器发送 GET 或者 POST 请求。
form 的重要参数

  • action:用来构造 HTTP 请求的 URL 是什么
  • method:用来构造 HTTP 请求的方法(form 只支持 GET 或 POST 方法)

input 的重要参数在 form 标签中的含义

  • type:表示输入框的类型(text 表示文本、password 表示密码、submit 表示提交按钮)
  • name:表示构造出的 HTTP 请求的 query string 的 key
  • value:表示 input 标签的值(对于 type 为 submit 类型来说,value 就对应了按钮上显示的文本)
  • input 标签的内容:表示 query string 的 value

当我们用 form 表单构造好了 HTTP 请求,点击 submit 提交按钮,就可以将请求发送出去
发送get请求

<formaction="https://www.sogou.com"method="get"><inputtype="text"name="username"><inputtype="password"name="password"><!-- 提交按钮,提交按钮中的内容可以通过value设置 --><inputtype="submit"value="提交"></form>

发送post请求

<!--只需要修改method即可--><formaction="https://www.sogou.com"method="post"><inputtype="text"name="username"><inputtype="password"name="password"><!-- 提交按钮,提交按钮中的内容可以通过value设置 --><inputtype="submit"value="提交"></form>

5. 通过 ajax 构造 HTTP 请求

**  ajax(Asynchronous Javascript And XML)** 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用 ajax)如果需要更新内容,必需重载整个网页面。
  这里的同步和异步与多线程的同步异步不同。这里的同步是调用者发送请求之后,一直等待被调用者发送的响应,异步调用者发送请求之后,就不管了,直到被调用者来通知才处理响应
  这里不使用 JavaScript 中原生的 ajax,而是用第三方库中 jQuery 里面提供的对 ajax 封装好的一个更简便的版本

注意

  • 使用 ajax 不仅可以实现 GET 和 POST 方法的请求,也可以实现其它方法的请求
  • 使用 ajax 不能跨域,即访问的域名和构造的域名需要相同(可以跨域的前提是该服务器允许可以跨域)

如何安装使用 jQuery 第三方库?
在 Javascript 中安装第三方库,只要在代码中引入对应库的 CDN 链接即可

  1. 搜索引擎搜索jQuery.cdn
  2. 打开jQuery的网页,比如: > jQuery.2
  3. 点开之后,复制jQuery对应的网页链接 > jQuery3
  4. 用浏览器打开链接,并把内容全选复制,之后新创建一个js文件,把内容全部粘贴到js文件,最后用script引入即可

CDN 是啥?
  CDN 的全称是 Content Delivery Network。即内容分发网络。CDN 是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率

jQuery 中的重要参数

  • $:是一个变量名,是 jQuery 中定义的一个对象。jQuery 里面的各种方法都是这个对象的成员
  • ajax:是 jQuery 封装好的 ajax 方法,其参数是一个对象,用来设置 HTTP 请求的一些参数
  • url:ajax 方法中用来设置 HTTP 请求的参数
  • method:ajax 方法中用来设置 HTTP 方法的参数
  • contentType:ajax 方法中用来设置 HTTP body 数据类型的参数
  • data:ajax 方法中用来设置 HTTP body 数据内容的参数
  • status:ajax 方法中用来表示状态码的参数
  • success:是一个回调函数,如果请求成功,响应返回后,浏览器就会自动调用这个参数

测试代码:

<script src="jQuery.js"></script><script>
    $.ajax({// 请求方法
        type:'get',// 请求url层次文件路径
        url:'https://baidu.com',
        success:function(body){// success对应一个回调函数// 这个函数会在正确获取到 HTTP 响应之后,来调用// "异步"// 回调函数的参数,就是 HTTP 响应的body部分
            console.log('获取到响应数据!' + body);},
        error:function(body){// error也对应一个回调函数// 这个函数会在请求失败后触发// "异步"
            console.log('获取响应失败!');}});</script>

结果:
**  浏览器打开之后,却是空白页面,打开控制台发现回调函数执行为error:**
ajax_error
**  原因就是因为跨域访问,浏览器是禁止 Ajax 进行跨域访问的。就是禁止跨越多个域名/服务器**

(五)HTTPS

  HTTPS 相当于 HTTP 的孪生兄弟。就是在 HTTP 的基础上,引入了一个加密层。就是对数据加密,防止运营商劫持。就像在很多时候,我们在网页上下载软件,下载之后却发现下载下的软件和我们想要的软件不一样。

1. HTTPS 的工作过程

  主要就是读密码进行加密,但是加密之后,也可以破解,但是破解的成本很高。HTTPS 当中引入的加密层,称为 SSL/TLS,主要的加密方式有两种:

  1. 对称加密:使用同一个密钥,既可以进行加密,也可以进行解密。
  2. 非对称加密。

对称加密
就像图片这样:
对称加密
  客户端和服务器持有同一个密钥,客户端传输的数据(HTTP 请求的 header 和 body)都通过这个密钥进行加密。然后再网络上传输的就是密文了。服务器在收到密文之后,接下来就可以根据密钥进行解密,拿到明文了。
  但是!一个服务器有很多客户端,如果都用同一个密钥的话,那黑客也接入客户端,就把其他客户端都破解了。所以一个客户端对应一个密钥。所以就要么是客户端生成密钥,要么就是服务器生成密钥,然后通过网络传送。我们假设是客户端生成密钥:
对称加密密钥约定
  客户端生成密钥,然后再通过网络告诉服务器,但是密钥如果用明文传输,也会让黑客拿到,加密也就没有意义了。所以使用对称加密,最大的问题就是:密钥无法安全传输到服务器,明文传输是不行的,所以必须继续对密钥加密,就成了套娃操作了。所以还得使用 :非对称加密。

非对称加密
  非对称加密,有两个密钥:公钥和私钥。公钥:人人都知道。私钥:只有自己才知道。使用公钥加密,私钥解密。或者私钥加密,公钥解密。
  基于非对称加密,服务器就可以自己生成一对公钥和私钥,公钥人人都能拿到。客户端使用公钥,对数据加密,然后把数据传给服务器,服务器再用私钥解密,但是非对称加密资源消耗很高,因此更常用的应该是用非对称密钥传递对称密钥,再用对称密钥进行消息传递,如下图。
非对称加密拿到密钥

那么接下来问题又来了:

  • 客户端如何获取到公钥?
  • 客户端如何确定这个公钥不是黑客伪造的?

**  客户端获取公钥时遇到的问题。客户端刚开始会问服务器要公钥,服务器返回公钥和私钥的时候,黑客拦截到服务器的公钥,然后黑客自己也生成一副公钥,私钥。把自己生成的公钥发给客户端。客户端加密之后,把密文发出去的时候,黑客再进行解密拦截解密。黑客为了隐藏自己,再用自己拿到的服务器的公钥加密,之后发给服务器,此时客户端,服务器之间使用的对称密钥黑客就截获到了,还是有问题。如下图所示:
公钥获取过程中间人攻击
解决中间人攻击:引入证书
  关键就是让客户端确认,当前的公钥是来自于服务器还是黑客。验证的时候,就通过第三方公信机构来验证,
关键在于证书不容易伪造,证书都是有着校验机制,并且客户端也能向公信机构求证**。就像是住酒店的时候,刷身份证,这也是通过公安局来验证的

二、传输层

  虽然传输层,是操作系统内核实现的,程序猿不需要直接和传输层打交道,但是传输层对我们来说仍然意义重大,在编写代码时,如果一切顺利,就还好,一旦代码出现一些bug,为了解决这些bug,传输层的一些知识就是必要的了

(一)UDP协议

UDP协议端格式
UDP协议格式

UDP报头结构

  1. 源端口(16位):表示自己的端口号
  2. 目的端口号(16位):表示传输对象的目的端口号
  3. 长度:这里是指UDP数据报的长度,这里的单位是字节,两个字节能表示的范围就是0 ~ 65535个字节,即64kB,那么数据部分占的大小就是0~65527,这种长度在几十年前肯定是够用的,但是随着计算机的发展,我们的硬盘和内存空间大了不少,要传输的数据也很多,64K就捉襟见肘了
  4. 检验和:又称为校验和,是用来验证网络通信传输的这个数据是否正确,因为光电信号可能会受到干扰,导致数据出错,重要的是,如果计算出的校验和显示数据不正确,那就一定不正确,但是如果校验和显示数据正确,不一定就是真的正确,是有一定误差的,虽然如此,校验和还是在数据传输中广泛使用

问题:
  上述的介绍中,一个UDP数据报能表示的长度很有限,因此如果要传一个比较大的数据,就要进行分包,然后再通过多个UDP数据报分别发送,接收方再把收到的数据报重新拼接成完整的数据,但是这种做法太麻烦了,拆包组包的代码很麻烦,还要考虑很多种情况(比如包丢了,包的顺序)

(二)TCP协议

TCP协议端格式(单位bit)
TCP协议格式

TCP协议报头格式
TCP协议报头格式

TCP报头结构

  1. 源端口和目的端口与UDP一致
  2. 序列号:表示当前是哪一条消息(具体理解可参照确认应答机制
  3. 确认号:表示当前是针对哪条消息进行应答
  4. 4位首部长度:表示TCP报头的长度,是可变的,这里的单位是4字节,意思是4位首部长度可以指定报头长度最大可以是60个字节
  5. 6位保留位:表示预留的空间,现在暂时不用,但是可能未来升级协议时就会用到
  6. 6个标志位:是TCP报文的核心字段,ACK为1,表示该报文是应答报文;SYN为1,表示该报文是同步报文段;FIN为1,表示该报文是结束报文段
  7. 16位窗口大小:说明接收方自己的缓冲区剩余容量大小,实际窗口大小不止64K,在选项中还包含一个窗口扩大因子M,实际窗口大小是窗口字段的值再左移M位
  8. 16位校验和:与UDP校验和作用一样
  9. 16位紧急指针
  10. 选项:可以有,也可以没有,可以有一个,也可以有多个

1. 确认应答机制(安全机制)

这是保证可靠传输的核心机制
  核心逻辑就是接收方收到消息之后,需要给发送方返回一个应答报文(ACK, acknowledge),表示自己已经收到
TCP确认应答机制
**  如上图,发送方在发送数据时,TCP将每个字节的数据都进行了编号,即序列号,1 ~ 666表示报头序号为1,报文长度为666,而每一个ACK都带有对应的确认序列号,意思是告诉发送方,“我已经收到了哪些数据,让发送方下一次从哪里开始发”**

2. 超时重传机制(安全机制)

  在上述的确认应答机制中,A给B发数据报,B收到并且返回应答报文,这种情况是正常情况下的过程,但是可能存在两种情况,导致这个过程有问题:

  1. 发送方的数据报发生丢包或时间超时
  2. 接收方的应答报文发生丢包

TCP超时重传机制
问题一:我们该如何确定是哪种情况呢?又该如何处理
  其实,我们不用确认是哪种情况,当主机A在规定时间内没有收到应答报文,那么主机A将会再次发送数据报

**问题二:如果是

ACK

丢失,那么意味着主机B将会收到很多重复数据,此时又该如何处理**
  那么就需要TCP协议能够识别哪些包是重复的包,并且把重复的包丢掉,在确认应答机制中的序列号就起到了作用,接收方收到数据会先放到操作系统内核的“接收缓冲区”,接收缓冲区可以看作是一个内存空间,并且是阻塞队列。当TCP收到新的数据的时候,就会根据序号检查这个数据是不是在接收缓冲区中已经存在了,如果不存在,就放进去,如果存在,就丢弃,保证应用程序调用socket api拿到的数据不重复。而主机B会隔一段时间向主机A发送应答报文,向主机A说明下面该传递哪些数据,因此不用担心主机A收不到应答报文,除非是网络异常

问题三:如果主机A一直收不到应答报文怎么办
  重传如果失败,TCP可能还会进行尝试,但是不会无休止的重传,连续几次重传都不行,就会认为网络可能出现了严重问题,就会选择断开连接。而重传的时间间隔也不是固定的,一般来说会逐渐变大(即重传频率降低),因为一次传输失败的概率本身比较小,连续几次丢包的概率小之又小

3. 连接管理机制(安全机制)

  基于以上两个机制,TCP的可靠性,就得到了有效的保证,但是TCP为了保证网络信号传输更高的可靠性,因此有了连接管理机制

(1)三次握手(建立连接)

TCP三次握手
三次握手过程

  1. 第一次握手(SYN):客户端主动发起连接请求,向服务器发送一个SYN同步报文段,如果TCP报文的报头中6位标识符中的SYN为1,标识当前报文是一个同步报文段,表示要和服务器建立连接
  2. 第二次握手(SYN,ACK):服务器在收到同步报文段之后,就会发送一个ACK报文(ACK为1)和SYN报文,ACK报文用来确认应答,SYN报文用来表示服务器也想和客户端建立连接;这第二次握手中的两个报文是一定会合在一起同时发的,直接将标志位的ACK和SYN都置为1,就可以实现封装一次,同时发送了
  3. 第三次握手(ACK):此时客服端发来ACK应答报文,双方建立连接成功

三次握手的可靠性解释:
**  三次握手的过程是为了检测网络是否满足可靠传输的基本条件**,第一次握手,服务器收到了客户端的SYN报文,服务器就知道了客户端的网络满足可靠传输,第二次握手,客户端收到了SYN、ACK报文,说明客户端就知道了自己和服务器的网络都满足可靠传输,第三次握手,是客户端告诉服务器,他自己的网络满足可靠传输,至此,双方都知道自己和对方的网络正常,那么就正式建立连接了

**  建立好连接之后,客户端和服务器就会在操作系统内核使用一定的数据结构来保存连接的相关信息,比如最重要的就是“五元组”**

认识几个重要的连接过程的状态

  1. LISTEN:表示服务器启动成功,端口绑定成功,随时可以与客户端建立连接
  2. ESTABLISHED:表示已经连接成功,随时可以进行通信

(2)四次挥手(断开连接)

TCP四次挥手
四次挥手过程

  1. 第一次挥手(FIN):一方向另一方发送了 FIN 请求,是结束报文段,该报文段的六位标志位中的FIN被置为1(四次挥手的发起端不一定是客户端,也可能是服务器
  2. 第二次挥手(ACK):另一方向一方发送了应答报文,表示知道了
  3. 第三次挥手(FIN):另一方向一方也发送了 FIN 请求
  4. 第四次挥手(ACK):一方也向另一方发送应答报文,表示知道了

问题一:为什么第二次挥手和第三次挥手不能合并在一起
  不能合并的原因在于另一方发送ACK和发送FIN的时机是不同的;**在三次握手中,ACK和SYN都是操作系统内核负责的,是同一时机;而四次挥手中,ACK是操作系统内核负责的,收到对方发的FIN之后,立即准备发送ACK,而FIN是用户代码负责的(只有用户代码中调用了

socket.close()

方法,才会触发 FIN),如果这俩操作时间差比较小,那么可能会合在一起发,如果时间差比较大,那么大概率不会合在一起**

认识几个重要的断开连接过程的状态

  1. CLOSE_WAIT:四次挥手挥了两次之后出现的状态,这个状态就是等待代码中调用socket.close()方法,来进行后续的挥手过程,正常情况下,一个服务器不会存在大量的CLOSE_WAIT,如果存在,大概率是代码有bug,导致close没有被执行到
  2. TIME_WAIT:谁主动发起了FIN,谁就进入TIME_WAIT状态,起到的效果,就是给最后一次ACK提供重传机会,如果主动方发完最后一次ACK后就断开连接,假如丢包了,被动方没有收到,那么被动方就会重新发送FIN,此时发送到主动方之后就无法对该请求进行处理了。因此主动方的连接就不应该释放太早,而是要等待一段时间,保证B不会重传FIN了,再真正销毁连接,等待的时间是两个MSL,MSL是指网络上任意两点之间,传输需要的最大时间。两个MSL就是一去一回的过程

4.滑动窗口(效率机制)

滑动窗口的意义就是在保证可靠性的前提下,尽量提高传输效率

图一
确认应答机制
图二
TCP滑动窗口

  如图一这种发送方式,由于确认应答机制的存在,导致当前每次执行一次发送操作,都要等待ACK的到达,然后才能继续发送,大量的时间都花在了等ACK上,传输效率极低
  如图二,就是滑动窗口机制,本质就是“批量的发送数据”,然后一起等一波ACK,一份等待时间等待了多份ACK,如果一次批量发送数据量为N,那么就称N为“窗口大小

问题一:能不能不等,一直传输呢
  必须得等,TCP是得保证可靠传输的,可靠传输的核心就是确认应答,如果不处理ACK,那么可靠传输就形同虚设

问题二:我们是等待所有ACK都到了才发,还是只要一个ACK到了,我们就继续发
  “滑动”的意思就是并不用把N组数据的ACK都等到,才继续往下发送,而是收到了一个ACK之后,就继续往下发一个。比如上图,只要1001的ACK收到了,主机A就会再发送一个4001 ~ 5000的数据报,此时等待ACK的范围就是(2001,3001,4001,5001),如下图,滑动窗口的范围就是需要等待的ACK的范围:

滑动窗口

问题三:因为数据是批量发送,如果丢包,该如何重传
第一种情况:数据报丢了
滑动窗口数据包丢了的情况
  如图,在这种情况下,接收方收到1 ~ 1000之后,返回1001的ACK,然后发送5001 ~ 6000,而1001 ~ 2000丢了,那么虽然后面接收方收到了2001 ~ 6000,并且把这些数据都保存到接收缓冲区了,接收方还是一直在向发送方索要1001 ~ 2000的数据,多次同样的ACK,就会触发发送方的重传机制,然后发送方就会只发送1001 ~ 2000,当接收方收到数据报之后,由于后面2001 ~ 6000都已经接收到了,因此直接向发送方发送6001的ACK应答报文,告诉发送方,从6001开始发送即可。即重传只是需要把丢了的那一块数据重传即可,其他已经到了的数据就不必重传了,整体的传输效率比较高,被称为快重传

第二种情况:ACK丢了
滑动窗口ACK丢了
  在这种情况下,主机A会收到2001的ACK,而2001的ACK的意思是2001之前的数据都收到了,这种情况下,即使1001的ACK丢包或者比2001到的慢,也没关系,主机A就知道2001之前的数据主机B都收到了,滑动窗口向后移动两个单元

5.流量控制(安全机制)

**  流量控制是在滑动窗口的基础上,目的是为了保证可靠性,在滑动窗口中,不仅要考虑发送方,还得考虑接收方,如果发送方发的太快,接收方处理不过来,就会丢包,还是要重新发送,不如调整发送速度,如图:**
流量控制

问题一,如何控制发送速度
**  如上图,接收方有一个接收缓冲区,我们可以将它理解为阻塞队列,而阻塞队列是一定有一个大小的,如果传过来的数据太多,势必会造成丢包,那么我们该如何控制发送速度呢,就需要接收方在收到发送的数据后,通过ACK报文来告知发送方自己剩余的容量大小,而这个数据就保存在TCP报头的16位窗口大小中**,当窗口容量降为0的时候,就不会再发送了

问题二,当容量为0的时候,发送方之后该如何得知什么时候能继续发送数据
**  发送方会隔一段时间向接收方发送一个窗口探测报文,这个报文中没有数据,只是为了触发ACK,了解如今接收方的剩余容量大小,如果不为0了,那么就继续发送数据**

6.拥塞控制(安全机制)

**  拥塞控制也是在滑动窗口的基础上来保证可靠性,因为两台主机之间发送数据,可能需要经历很多的设备,可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起大量丢包问题,得不偿失**
  因此为了摸清网络状况,TCP引入了慢启动机制,先发少量的数据,测测网速,再决定按照多大的速度传输数据

TCP拥塞控制

拥塞控制图分析
  如上图,就是通过拥塞窗口的大小,来制约滑动窗口的大小,滑动窗口的大小 = min(流量控制窗口,拥塞窗口)。最开始的时候,拥塞窗口取的非常小,只有1个单位,然后先进行指数增长,让拥塞窗口快速增长到快要丢包但是还没丢包的大小,提高效率;指数增长到一定程度就进入了线性增长阶段,慢慢增长进行探测;而一直增长增长,势必会达到网络拥塞的地步,就会引发丢包,一旦丢包,拥塞窗口就直接降为最小

问题一:阈值的作用和更新
  刚开始16就是当前的阈值,当拥塞窗口的大小达到阈值之后,拥塞窗口的增长就由指数增长改为线性增长;并且阈值也不是一成不变的,当出现丢包之后,阈值就降为了原来最大拥塞窗口的一半

问题二:出现丢包之后为什么直接降为最小
  原因就是出现丢包,可能是网络不好,而如果网络不好了,我们只降一点点解决不了问题,甚至会造成更多的丢包,于是干脆直接降到最低,来保证传输的可靠性

7.延时应答(效率机制)

**  延时应答是在流量控制的基础上进行的优化,流量控制是控制传输的速度,当窗口小的时候让速度慢下来;而延时应答,则是在这个基础上,尽可能的让发送方多发一些数据**
TCP延时应答

延时应答图说明
  当主机A向主机B发送了1 ~ 1000之后,它不会立即应答,而是稍微等一下,有可能在这等待的一段时间里,接收缓冲区的剩余容量就可能增加一些,此时再返回ACK报文,告知剩余容量,来让主机A发送更多的数据,因此这个操作就是在有限的情况下,尽可能的提高传输速度
  可以采取下面的延时应答方法:

  • 数量限制:每隔N个包就应答一次;
  • 时间限制:超过最大延迟时间就应答一次

8.捎带应答(效率机制)

服务器和客户端之间的通信主要是下面几种模型

  1. 一问一答,请求和响应
  2. 多问一答,上传文件
  3. 一问多答,下载文件
  4. 多问多答,直播

**  而捎带应答机制,就可以提高一问一答这种模型的效率,如下图,ACK是内核响应的,会立即执行,而“响应”是应用程序执行到相关的代码才会发送的,这两个报文是不同时机触发的,理论上不应该合并,但是因为延时应答机制,导致ACK不一定是立即返回的,而ACK响应推迟,那么ACK报文就有可能和应用程序的“响应”报文的返回时机重合,这时,就可以把ACK和响应数据合二为一**
TCP捎带应答

9.面向字节流(粘包问题)

  不仅仅TCP存在粘包问题,其他的面向字节流的机制,也存在该问题,比如读文件,这里的粘包,粘的是应用层的数据报,在TCO接收缓冲区中,若干应用层数据报混在了一起

粘包问题举例
  比如客户端向服务器发了好几份数据报,这些数据报在到达服务器之后,就会进行分用,而当内核把TCP的报文分用之后,把数据放在缓冲区供应用层读取,但是由于我们已经分用了,我们就分不清哪些数据是一个包里面了,该读多少我们并不清楚

粘包问题解决方案
  本身粘包问题对TCP的传输没有任何影响,但是会影响到应用层读取数据,因此我们可以在应用层约定一种规则,明确包的边界,然后按照规则把数据进行切分,那么我们就可以知道一份数据是从哪到哪了,比如-数据-,使用“-”把数据进行分割

10.TCP异常处理

TCP异常情况

  1. 进程终止
  2. 机器正常关机
  3. 机器断电/网线断开

(1)进程终止

  这里说的是正常的终止,比如在任务管理器关闭进程,或者在桌面手动关闭页面和后台程序。

异常处理
  实际上,TCP连接,是通过 socket 建立的,socket本质上是进程打开的一个文件,文件保存在进程PCB的文件描述符表中,每次打开一个文件(包括socket),都会在文件描述符表中增加一项,如果close文件,那么就会在文件描述符表中删除一项,而如果直接终止进程,PCB就没了,里面的文件描述符表也就没了,此时的所有文件都会进行关闭,而关闭的过程就和手动close一样,都会触发四次挥手过程,因此进程终止执行的是正常的TCP中断连接过程P

(2)机器正常关机

  这里的关机是指点击操作系统的关机键,让系统正常关机,而这种操作和进程终止操作一毛一样

(3)机器断电/网线断开

  这里的机器断电以台式机为例,台式机被直接拔掉电源,进程就根本没有反应时间,无法进行正常的TCP四次挥手断开连接过程

导致的结果

比如客户端和服务器正在进行网络传输
  服务器断电关机,那么客户端发过去的数据报就再也收不到ACK了,此时就会触发超时重传机制,重传了几次之后,依然没有收到ACK,客户端就会认为这个连接出现了严重故障,接着就会尝试重新建立连接,尝试失败,就会放弃连接(删除之前与服务器相关的连接信息)
  客户端断电关机,那么由于服务器是被动接收数据的一方,因此就不清楚客户端是暂时没有数据还是挂了,因此就会隔一段时间发送一个探测报文(这种探测报文又称为“心跳包”),不带有实际数据,只是为了触发客户端的ACK,重复几次,服务器发现客户端没有传过来ACK应答报文,那么就会认为A出现了问题,因此也会尝试重传,尝试失败,放弃链接

(三)TCP VS UDP

什么时候用TCP,什么时候用UDP

  1. 如果对可靠性要求比较高或者包比较大,那么就基于TCP开发
  2. 如果对可靠性要求不高,对效率要求更高,就选择UDP(比如机房内部的主机间通信)

经典面试题:基于UDP如何实现可靠传输(直接参考TCP)

三、网络层

IP协议

IP协议主要完成两方面工作

  1. 地址管理
  2. 路由选择

IP协议报头
IP报头
IP报头结构

  1. 4位版本号:IP协议的版本号,当前只有两个取值,4(0100,IPv4)和6(0110,IPv6)
  2. 4位头部长度:IP报头和TCP类似,是可变的,带有选项,单位也是4字节
  3. 8位服务类型(TOS):只有四位有效,包括最小延时、最大吞吐量、最高可靠性、最小成本(同一时刻只能选择一种),这四个选项都是为了选择最优路径,但是最优路径也分什么最优
  4. 16位总长度:与UDP类似,IP的数据报最大长度也是不能超过64K,但是IP协议自身是实现了分包组包的操作,就是下面三个标识符
  5. 16位标识:被拆出的同一个TCP数据报的16位标识的值是相同的
  6. 13位片偏移:对同一个TCP的多个包进行标记,描述谁先谁后
  7. 3位标志:标识当前是否是TCP分成的最后一个包,标记为1,表示这是最后一个包(结束标记),为0,说明后面还有
  8. 8位生存时间(TTL):表示一个IP数据报,在网络上还能存在多久,单位是转发次数,IP数据报每经过一个路由器,TTL - 1,如果TTL耗尽,那么收到这个包的路由器就把这个包丢掉(原因就是有些包里的IP地址永远也到不了,又不能让它无休止的在网络上转发)
  9. 8位协议:表示传输层是使用的哪种协议,TCP和UDP都有不同的取值
  10. 16位头部校验和:用来校验数据是否正确
  11. 32位源IP和目的IP:源IP就表示发送方地址,目的IP就表示接收方地址,对于IPv4,由于32位比特位人不好记,于是使用“点分十进制”的方式显示,把32位分成4部分,每个部分1个字节,范围就是0 ~ 255
  12. 选项:不定长,最多40字节

衍生出一个面试题:如何基于UDP,在应用层实现分包组包,参考IP协议的操作

1. 地址管理

IP地址分成两个部分,网络号和主机号,比如“127.0.0.1”中“127.0.0”就是网络号,最后的“1”就是主机号

  1. 网络号:描述当前的网段信息(局域网的标识)
  2. 主机号:区分了局域网内部的主机

要求:同一个局域网里,主机之间的网络号是相同的,主机号不同,两个相邻的局域网之间(同一个路由器之间连接),网络号也不同
  值得一提的是,路由器也有IP地址,并且至少有两个,LAN口有一个自己负责的局域网的IP地址,称为内网IP(网络号是自己的局域网里的网络号),WAN口和其他路由器相连,也对应一个IP地址,称为外网IP(网络号是相邻局域网的网络号)

(1)子网掩码

**  网络号和主机号的位数不一定就是24位和8位,具体的位数需要看子网掩码**
  子网掩码也是一个32位,点分十进制的整数,子网掩码的左侧全为1,右侧全为0,左侧的1就表示哪些位是网络号,右侧的0就表示哪些位是主机号
  最常见的子网掩码就是255.255.255.0,如果一个局域网设备多了,子网掩码就会出现一些其他值,需要根据实际需要来确定网段如何划分(每个设备的IP都是可配置的,包括子网掩码也可修改)

(2)特殊IP地址

  1. 如果 IP 主机号为全0,该IP号就表示网络号(局域网里一个正常的设备,主机号不能为0)
  2. 如果 IP 的主机号为全1,该IP就是“广播地址”,往这个广播地址上发消息,整个局域网都能收到
  3. IP地址是 127 开头的,该IP就表示“环回IP”,表示主机自己,127.0.0.1就是环回IP的典型代表
  4. IP地址是10开头的,192.168开头的,172.16 ~ 172.31开头的,表示该IP地址是一个局域网内部的IP(内网IP),除此之外,剩下的IP称为外网IP(直接在广域网上使用的IP)
  5. 要求外网IP必须唯一,每个外网IP对应到唯一的一个设备,内网IP只是在当前局域网中是唯一的,不同的局域网,可以有相同的内网IP的设备

(3)内网IP地址相同的原因

  当前IPv4协议,使用的 IP 地址是32位整数,能表示的范围是42亿9千万,但是随着网络发展,世界上的设备早已经超过42亿9千万,尤其是移动互联网的兴起,手机也要分配 IP 地址,因此,让每个设备都有唯一的 IP 地址,不现实
解决方案

  1. 动态分配IP地址,让每个设备联网的时候才有 IP,每联网的时候就没有 IP,这个方案可以缓解,但是不能从根本上解决问题,毕竟设备没有减少,IP地址也没有增加
  2. NAT机制,让多个设备共用一个IP(外网IP),将网络分为了外网(广域网)和内网(局域网),比如我们自己的设备是没有外网IP的,但是运营商有,比如我们上网百度的时候,百度服务器看到的就是运营商的外网IP,我们的数据报在经过运营商的路由器时,IP地址就会被修改为外网IP,带有这样功能的路由器设备,被称为NAT设备   一个外网IP可能表示着几千上万的设备**  那么如何保证使用相同外网IP的设备同时访问一个服务器的时候服务器能正确区分?** 进一步区分,就需要依靠端口号,而运营商的路由器会保证传出去的数据报端口号不同**  因此就有一个重要的结论**:对于一个外网IP,在互联网上任意位置都能访问到,对于一个内网IP,只能访问当前局域网的设备,不能访问其他局域网中的设备,就是因为内网IP可以重复出现   但是一个局域网里端口号最多65535,那么如果端口号不够了,又会引发问题
  3. IPv6,IPv6在报头中使用了一个更长的字段来表示 IP 地址,16个字节,128位,非常非常大的数据,真正从根本上解决了IP地址不够用的问题   但有个最大的问题,IPv6和IPv4是不兼容的,对于一个设备来说,支持IPv4和IPv6需要两个截然不同的机制,现有的大量的网络设备(比如路由器),很可能都是只支持IPv4,不支持IPv6

2. 路由选择

**  路由选择,也就是路径规划,两个设备之间,要找到一条通道,能够完成传输的过程**
  IP数据报中的目的地址,表示了这个包要发到哪里,如果传到一个路由器,这个路由器就认识这个目标地址,就会直接说明该怎么走,如果当前路由器不认识,就会说明大致方向,让数据报到下一个路由器再看,一直走,一直在接近目标,总会到达一个知道路的路由器,那么就可以具体的转发过去了,可能有的路由器不光认识,还知道多条路径,那么就可以选择一条更合适的路线
**  路由器如何认识IP地址,在路由器内部维护了一个数据结构,路由表,它是有一系列专门的路由表生成算法,自动生成的,也可以手动配置,而路由表里面就记录了一些网段信息(网络号,目的IP就在这些网络号中匹配)以及每个网络号对应的网络接口(网络接口就对应到路由器里面的具体端口)**

四、数据链路层

**  数据链路层主要的协议,叫做“以太网”,平时插的网线,就叫做“以太网线”,以太网这个协议不仅仅规定了数据链路层的内容,也规定了物理层的内容**

核心结构:以太网数据帧
以太网数据帧

以太网数据帧结构

  1. 源地址和目的地址:6个字节,比IPv4长了六万多倍,被称为“mac地址”,IP地址没做到的唯一,mac地址做到了每个设备唯一(每个网卡都是唯一的,在网卡出厂时就写死了)   mac地址和IP地址的作用其实有些重复了,因此现状就是mac地址和IP地址同时使用,表示不同的功能,IP地址用来表示传输的起点和终点,mac地址用来表示传输过程中,任意两个相邻节点之间的地址
  2. 类型:如上图所示,0800是一般情况,0808,8035都是特殊情况,0800就是表示后面的数据报是IP数据报
  3. CRC:帧尾,是一个基于CRC算法(循环冗余算法)的校验和
  4. 中间数据的1500字节:被称为MTU,是指一个以太网数据帧能够承载的数据范围,这个范围取决于硬件设备。以太网是和硬件密切相关的,不同的硬件设备,对应的数据链路层协议,可能就不一样,MTU也不相同。数据链路层需要考虑的是相邻设备之间的传输,因此就要考虑不同设备之间的承载量,而IP的分包,不只是给IP的报头64k准备,更多的是为了适应不同的MTU   换句话说,虽然TCP是面向字节流,但是数据量还是受限于MTU,而MTU又分为三部分,IP长度,TCP长度,数据长度(MSS),因此我们说,当数据长度不超过MSS时,是最高效的

ARP协议
  ARP报文不是用来传输数据的,而是根据协议建立起IP -> mac地址的映射关系。由于路由器会分用到网络层,根据IP地址来规划接下来的路线,因此就需要这样的映射关系,在封装以太网数据帧的时候,明白目的mac是啥
做法:当设备启动时,会向局域网中广播ARP报文,每个设备收到后,给出应答,应答中就包含了自己的IP和mac,发起广播的设备就能根据这些应答建立起映射表了

标签: 网络 http https

本文转载自: https://blog.csdn.net/fear_wolf/article/details/128765307
版权归原作者 求索1024 所有, 如有侵权,请联系我们删除。

“网络原理之HTTP/HTTPS、TCP、IP四层协议栈”的评论:

还没有评论