计算机网络核心知识点大梳理

thinkingme2022年12月13日
大约 74 分钟

计算机网络核心知识点大梳理

作者:月伴飞鱼,转载链接:https://mp.weixin.qq.com/s/7EddtzpwIRvYfw34QE4zvwopen in new window

OSI 七层模型

物理层

首先解决两台物理机之间的通信需求,具体就是机器 A 往机器 B 发送比特流,机器 B 能收到比特流。

物理层主要定义了物理设备的标准,如网线的类型,光纤的接口类型,各种传输介质的传输速率。

主要作用是传输比特流(0101二进制数据),将比特流转化为电流强弱传输,到达目的后再转化为比特流,即常说的数模转化和模数转换。

这层数据叫做比特。网卡工作在这层

物理层是 OSI 七层模型的物理基础,没有它就谈不上数据传输了

物理层就是由实物所承载的,所以作比喻的话,公路、汽车和飞机等承载货物(数据)的交通工具,就是物理层的象征

数据链路层

在传输比特流的过程中,会产生错传、数据传输不完整的可能。

数据链路层定义了如何格式化数据进行传输,以及如何控制对物理介质的访问。通常提供错误检测和纠正,以确保数据传输的准确性。

本层将比特数据组成帧,交换机工作在这层,对帧解码,并根据帧中包含的信息把数据发送到正确的接收方。

该层负责物理层面上互连的节点之间的通信传输。例如与 1 个以太网相连的两个节点间的通讯。

常见的协议有 HDLC、PPP、SLIP

数据链路层会将0、1序列划分为具有意义的数据帧传送给对端(数据帧的生成与接收

网络层

随着网络节点的不断增加,点对点通讯需要通过多个节点,如何找到目标节点,如何选择最佳路径成为首要需求。

网络层主要功能是将网络地址转化为对应的物理地址,并决定如何将数据从发送方路由到接收方。

网络层通过综合考虑发送优先权、网络拥塞程度、服务质量以及可选路由的花费来决定从一个网络中节点 A 到另一个网络中节点 B 的最佳路径。

由于网络层处理并智能指导数据传送,路由器连接网络隔断,所以路由器属于网络层。

此层的数据称之为数据包。本层需要关注的协议TCP/IP协议中的 IP 协议。

网络层负责将数据传输到目标地址。目标地址可以使多个网络通过路由器连接而成的某一个地址。因此这一层主要负责寻址和路由选择。主要由 IP、ICMP 两个协议组成

网络层将数据从发送端的主机发送到接收端的主机,两台主机间可能会存在很多数据链路,但网络层就是负责找出一条相对顺畅的通路将数据传递过去。传输的地址使用的是 IP 地址。IP 地址通过不断转发到更近的 IP 地址,最终可以到达目标地址

传输层

随着网络通信需求的进一步扩大,通信过程中需要发送大量的数据,如海量文件传输,可能需要很长时间,网络在通信的过程中会中断很多次,此时为了保证传输大量文件时的准确性,需要对发送出去的数据进行切分,切割为一个一个的段落(Segement)发送,其中一个段落丢失是否重传,段落是否按顺序到达,是传输层需要考虑的问题。

传输层解决了主机间的数据传输,数据间的传输可以是不同网络,并且传输层解决了传输质量的问题。

传输层需要关注的协议有 TCP/IP 协议中的TCP协议和UDP协议。

会话层

自动收发包,自动寻址。

会话层作用是负责建立和断开通信连接,何时建立,断开连接以及保持多久的连接。常见的协议有 ADSP、RPC

表示层

Linux 给 WIndows 发包,不同系统语法不一致,如 exe 不能在Linux下执行,shell 不能在 Windows 不能直接运行。于是需要表示层。

解决不同系统之间通信语法问题,在表示层数据将按照网络能理解的方案进行格式化,格式化因所使用网络的不同而不同。

它主要负责数据格式的转换。具体来说,就是讲设备固有的数据格式转换为网络标准格式。常见的协议有ASCII、SSL/TLS

应用层

规定发送方和接收方必须使用一个固定长度的消息头,消息头必须使用某种固定的组成,消息头中必须记录消息体的长度等信息,方便接收方正确解析发送方发送的数据。

应用层旨在更方便应用从网络中接收的数据,重点关注TCP/IP协议中的 HTTP 协议

四层传输层数据被称作(Segments);

三层网络层数据被称做(Packages);

二层数据链路层时数据被称为(Frames);

一层物理层时数据被称为比特流(Bits)。

TCP 和 IP 模型

OSI 模型注重通信协议必要的功能;TCP/IP 更强调在计算机上实现协议应该开发哪种程序

TCP/IP 划分了四层网络模型

  • 第一层:应用层,主要有负责 web 浏览器的 HTTP 协议, 文件传输的 FTP 协议,负责电子邮件的 SMTP 协议,负责域名系统的 DNS 等
  • 第二层:传输层,主要是有可靠传输的 TCP 协议,特别高效的 UDP 协议。主要负责传输应用层的数据包。
  • 第三层:网络层,主要是 IP 协议。主要负责寻址(找到目标设备的位置)
  • 第四层:数据链路层,主要是负责转换数字信号和物理二进制信号。

四层网络协议的作用

  • 发送端是由上至下,把上层来的数据在头部加上各层协议的数据(部首)再下发给下层。
  • 接受端则由下而上,把从下层接受到的数据进行解密和去掉头部的部首后再发送给上层。
  • 层层加密和解密后,应用层最终拿到了需要的数据。

举个例子:

我们需要发送一个index.html

两台电脑在应用层都使用 HTTP 协议(即都使用浏览器)。

在传输层,TCP 协议会将 HTTP 协议发送的数据看作一个数据包,并在这个数据包前面加上 TCP 包的一部分信息(部首)

在网络层,IP 协议会将 TCP 协议要发送的数据看作一个数据包,同样的在这个数据包前端加上 IP 协议的部首

在数据链路层,对应的协议也会在 IP 数据包前端加上以太网的部首。

源设备和目标设备通过网线连接,就可以通过物理层的二进制传输数据。

数据链路层,会使用对应的协议找到物理层的二进制数据,解码得到以太网的部首信息和对应的 IP 数据包,再将 IP 数据包传给上层的网络层。

数据链路层>网络层>传输层>应用层,一层层的解码,最后就可以在浏览器中得到目标设备传送过来的index.html

TCP/IP 协议族

从字面意义上来讲,TCP/IP 是指传输层的 TCP 协议和网络层的 IP 协议。

实际上,TCP/IP 只是利用 IP 进行通信时所必须用到的协议群的统称。

具体来说,在网络层是 IP/ICMP 协议、在传输层是 TCP/UDP 协议、在应用层是 SMTP、FTP、以及 HTTP 等。他们都属于 TCP/IP 协议。

网络设备

交换机

交换机可以接入多台电脑

每个电脑网卡的 MAC 地址都是不一样的,电脑发送数据时,数据头部携带网卡的 MAC 地址,用 MAC 地址标识来不同的电脑

交换机就可以识别数据头部的 MAC 地址来区分不同的电脑

交换机除了能识别不同的电脑,还需要找到电脑连接的交换机端口,才能顺利的把数据从相应端口发送出去

交换机通过自学机制,把学习到的设备 MAC 地址和交换机端口号添加到 MAC 地址表,并根据 MAC 地址表进行数据转发

路由器

交换机需要记录的 MAC 地址表也越来越多,需要的交换机也越来越多

但是交换机的容量和性能有限,MAC 地址表无法记录全世界电脑的 MAC 地址和对应的端口号,MAC 地址表太大也无法快速查找到对应的 MAC 地址表项

于是就有了三层网络设备路由器,路由器可以把全世界的网络连接起来

局域网内的网络连接可以使用交换机,例如一个公司内的网络或者一个校园内的网络通过交换机连接

不同区域的局域网互联使用路由器

那么如何区分不同的网络区域呢?又是如何跨网络区域进行数据转发的呢?

路由器有多个端口,分别连接不同的网络区域,不同网络区域的 IP 地址网络号不同

它通过识别目的 IP 地址的网络号,再根据路由表进行数据转发

HTTP

请求方法

HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。

HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

序 号方法描述
1GET请求指定的页面信息,并返回实体主体。
2HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
3POST向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
4PUT从客户端向服务器传送的数据取代指定的文档的内容。
5DELETE请求服务器删除指定的页面。
6CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
7OPTIONS允许客户端查看服务器的性能。
8TRACE回显服务器收到的请求,主要用于测试或诊断。
9PATCH是对 PUT 方法的补充,用来对已知资源进行局部更新 。

GET 请求和 POST 请求的区别

  1. GET 请求的请求参数是添加到 head 中,可以在 url 中可以看到;POST 请求的请求参数是添加到 body 中,在 url 中不可见。
  2. 请求的 url 有长度限制,这个限制由浏览器和 web 服务器决定和设置的,例如 IE 浏览器对 URL 的最大限制为 2083 个字符,如果超过这个数字,提交按钮没有任何反应,因为 GET 请求的参数是添加到 URL 中,所以 GET 请求的 URL 的长度限制需要将请求参数长度也考虑进去。而 POST 请求不用考虑请求参数的长度。
  3. GET 请求产生一个数据包; POST 请求产生 2 个数据包,在火狐浏览器中,产生一个数据包,这个区别点在于浏览器的请求机制,先发送请求头,再发送请求体,因为 GET 没有请求体,所以就发送一个数据包,而 POST 包含请求体,所以发送两次数据包,但是由于火狐机制不同,所以发送一个数据包。
  4. GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
  5. GET 是幂等的,而 POST 不是(幂等表示执行相同的操作,结果也是相同的)
  6. GET 是获取数据,POST 是修改数据

状态码

状态码由 3 位数字组成,第一位定义响应的类别

1XX:指示信息,表示请求以接收,继续处理

2XX:成功,表示请求已经被成功接收、理解、接受

  • 200 OK 是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。

  • 204 No Content 也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。

  • 206 Partial Content 是应用于 HTTP 分块下载或断电续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。

3XX:状态码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向

  • 301 Moved Permanently 表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问,搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址。
  • 302 Moved Permanently 表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问,搜索引擎会抓取新的内容而保存旧的网址。

301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。

  • 304 Not Modified 不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。

4XX:状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。

  • 400 Bad Request 表示客户端请求的报文有错误。

  • 401 Unauthorized:缺失或错误的认证,这个状态代码必须和 WWW-Authenticate 报头域一起使用。

  • 403 Forbidden 表示服务器禁止访问资源,并不是客户端的请求出错。

  • 404 Not Found 表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。

5XX:状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。

  • 501 Not Implemented 表示客户端请求的功能还不支持。

  • 502 Bad Gateway 通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。

  • 503 Service Unavailable 表示服务器当前很忙,暂时无法响应服务器。

  • 504 Gateway Timeout:网关超时,由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答。

301 和 302 的区别

301 重定向,指页面永久性转移,表示为资源或页面永久性地转移到了另一个位置。

301 是 HTTP 协议中的一种状态码,当用户或搜索引擎向服务器发出浏览请求时,服务器返回的 HTTP 数据流中头信息中包含状态码 301 ,表示该资源已经永久改变了位置。

302 重定向是页面暂时性转移,搜索引擎会抓取新的内容而保存旧的网址并认为新的网址只是暂时的。

HTTP1.1

长连接

HTTP 1.1 支持长连接

HTTP 1.0 规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个 TCP 连接,服务器完成请求处理后立即断开 TCP 连接,服务器不跟踪每个客户也不记录过去的请求。

HTTP 1.1 则支持持久连接 Persistent Connection,并且默认使用,在同一个 TCP 的连接中可以传送多个 HTTP 请求和响应,多个请求和响应可以重叠,多个请求和响应可以同时进行,更加多的请求头和响应头

HTTP 1.1 的持续连接,也需要增加新的请求头来帮助实现,例如,Connection 请求头的值为 Keep-Alive 时,客户端通知服务器返回本次请求结果后保持连接;Connection 请求头的值为 Close 时,客户端通知服务器返回本次请求结果后关闭连接。

管道网络传输

HTTP/1.1 采用了长连接的方式,这使得管道网络传输成为了可能。

即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求,管道机制则是允许浏览器同时发出 A 请求和 B 请求。

但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求,要是 前面的回应特别慢,后面就会有许多请求排队等着。

Host 字段

在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名,但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个 IP 地址。

HTTP1.1 的请求消息和响应消息都应支持 Host 头域,且请求消息中如果没有 Host 头域会报告一个错误(400 Bad Request)。

此外,服务器应该接受以绝对路径标记的资源请求。

100Status

HTTP/1.1 加入了一个新的状态码 100。

客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码 401(Unauthorized);

如果服务器接收此请求就回送响应码 100,客户端就可以继续发送带实体的完整请求了。

100 状态代码的使用,允许客户端在发 request 消息 body 之前先用 request header 试探一下 server,看 server 要不要接收 request body,再决定要不要发 request body。

Chunked Transfer Coding

HTTP/1.1 将发送方将消息分割成若干个任意大小的数据块,每个数据块在发送时都会附上块的长度,最后用一个零长度的块作为消息结束的标志。

这种方法允许发送方只缓冲消息的一个片段,避免缓冲整个消息带来的过载。

Cache

HTTP/1.1 在 1.0 的基础上加入了一些 Cache 的新特性,当缓存对象的 Age 超过 Expire 时变为 Stable 对象,Cache 不需要直接抛弃 Stable 对象,而是与源服务器进行重新激活。

HTTP2.0

HTTP2.0 和 HTTP1.X 相比的新特性

  • 新的二进制格式,HTTP1.x的解析是基于文本

  • 多路复用,即连接共享,即每一个 request 都是是用作连接共享机制的,一个 request 对应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面

  • header 压缩,HTTP1.x的 header 带有大量信息,而且每次都要重复发送,HTTP2.0 使用 encoder 来减少需要传输的 header 大小,通讯双方各自 cache 一份 header fields 表,既避免了重复 header 的传输,又减小了需要传输的大小

  • 服务端推送

HTTP/2 还在一定程度上改善了传统的请求 - 应答工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。

举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送。

数据流

HTTP/2 的数据包不是按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。

因此,必须要对数据包做标记,指出它属于哪个回应。

每个请求或回应的所有数据包,称为一个数据流(Stream)。

每个数据流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数

客户端还可以指定数据流的优先级。优先级高的请求,服务器就先响应该请求。

HTTP2.0 的多路复用和 HTTP1.X 中的长连接复用有什么区别

  • HTTP/1.1 的 Pipeling 为若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法;
  • HTTP2.0 多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行

HTTP3.0

使用 UDP 协议

HTTP/2 主要的问题在于:多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的。

所以一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来

  • HTTP/1.1 中的管道传输中如果有一个请求阻塞了,那么队列后请求也统统被阻塞住了
  • HTTP/2 多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。

这都是基于 TCP 传输层的问题,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!

总结

HTTP/1.1采用FIFO管道请求响应队列,也就是说当第一个请求后端处理过慢,就会阻塞住后来的请求。

而HTTP/2为了解决上面的问题,为每个请求设置编号,这样每个数据包可以通过编号来响应对应的请求,不需要等待先来的请求响应完毕。

但是如果丢包了,依旧会堵塞住整个管道,这就有了http3。

HTTPS

HTTP 与 HTTPS 的区别

HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全

  • HTTPS 比 HTTP 更加安全,对搜索引擎更友好,利于 SEO,谷歌、百度优先索引 HTTPS 网页

  • HTTPS 需要用到 SSL 证书,而 HTTP 不用

  • HTTPS 标准端口 443,HTTP 标准端口 80

  • HTTPS 基于传输层,HTTP 基于应用层

  • HTTPS 在浏览器显示绿色安全锁,HTTP 没有显示

工作原理

HTTPS 协议会对传输的数据进行加密,而加密过程是使用了非对称加密实现

HTTPS 的整体过程分为证书验证和数据传输阶段,具体的交互过程如下:

  • Client 发起一个 HTTPS 的请求
  • Server 把事先配置好的公钥证书返回给客户端。
  • Client 验证公钥证书:比如是否在有效期内,证书的用途是不是匹配 Client 请求的站点,是不是在 CRL 吊销列表里面,它的上一级证书是否有效,这是一个递归的过程,直到验证到根证书(操作系统内置的 Root 证书或者 Client 内置的 Root 证书),如果验证通过则继续,不通过则显示警告信息。
  • Client 使用伪随机数生成器生成加密所使用的对称密钥,然后用证书的公钥加密这个对称密钥,发给 Server。
  • Server 使用自己的私钥解密这个消息,得到对称密钥。至此,Client 和 Server 双方都持有了相同的对称密钥。
  • Server 使用对称密钥加密明文内容 A,发送给 Client。
  • Client 使用对称密钥解密响应的密文,得到明文内容 A。
  • Client 再次发起 HTTPS 的请求,使用对称密钥加密请求的明文内容 B,然后 Server 使用对称密钥解密密文,得到明文内容 B。

数字证书

客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。

这就存在些问题,如何保证公钥不被篡改和信任度?

所以这里就需要借助第三方权威机构 CA (数字证书认证机构),将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的。

通过数字证书的方式保证服务器公钥的身份,解决冒充的风险。

请求报文

请求头

HTTP 请求报文由 3 部分组成(请求行+请求头+请求体)

常见的 HTTP 报文头属性

  • Accpet
    • 告诉服务端,客户端接收什么类型的响应
  • Referer
    • 表示这是请求是从哪个 URL 进来的,比如想在网上购物,但是不知道选择哪家电商平台,你就去问度娘,说哪家电商的东西便宜啊,然后一堆东西弹出在你面前,第一给就是某宝,当你从这里进入某宝的时候,这个请求报文的 Referer 就是:www.baidu.com
  • Cache-Control
    • 对缓存进行控制,如一个请求希望响应的内容在客户端缓存一年,或不被缓可以通过这个报文头设置
  • Accept-Encoding
    • 这个属性是用来告诉服务器能接受什么编码格式,包括字符编码,压缩形式(一般都是压缩形式)
      • 例如:Accept-Encoding:gzip, deflate(这两种都是压缩格式)
  • Host
    • 指定要请求的资源所在的主机和端口
  • User-Agent:告诉服务器,客户端使用的操作系统、浏览器版本和名称
  • Connection

决定当前事务(三次握手和四次挥手)完成后,是否关闭网络连接。

  • 持久连接,事务完成后不关闭网络连接 : Connection: keep-alive
  • 非持久连接,事务完成后关闭网络连接: Connection: close

响应报文

响应报文与请求报文一样,由三个部分组成(响应行,响应头,响应体)

HTTP 响应报文属性

  • Cache-Control
    • 响应输出到客户端后,服务端通过该属性告诉客户端该怎么控制响应内容的缓存
  • ETag
    • 表示你请求资源的版本,如果该资源发生啦变化,那么这个属性也会跟着变
  • Location
    • 在重定向中或者创建新资源时使用
  • Set-Cookie
    • 服务端可以设置客户端的 cookie

TCP

TCP 是一个传输层协议,提供可靠传输,支持全双工,是一个连接导向的协议。

双工/单工

在任何一个时刻,如果数据只能单向发送,就是单工。

如果在某个时刻数据可以向一个方向传输,也可以向另一个方向反方向传输,而且交替进行,叫作半双工;半双工需要至少 1 条线路。

如果任何时刻数据都可以双向收发,这就是全双工,全双工需要大于 1 条线路。

TCP 是一个双工协议,数据任何时候都可以双向传输。

这就意味着客户端和服务端可以平等地发送、接收信息。

TCP 协议的主要特点

  • TCP 是面向连接的运输层协议;所谓面向连接就是双方传输数据之前,必须先建立一条通道,例如三次握手就是建议通道的一个过程,而四次挥手则是结束销毁通道的一个其中过程。

  • 每一条 TCP 连接只能有两个端点(即两个套接字),只能是点对点的;

  • TCP 提供可靠的传输服务。传送的数据无差错、不丢失、不重复、按序到达;

  • TCP 提供全双工通信。允许通信双方的应用进程在任何时候都可以发送数据,因为两端都设有发送缓存和接受缓存;

  • 面向字节流。虽然应用程序与 TCP 交互是一次一个大小不等的数据块,但 TCP 把这些数据看成一连串无结构的字节流,它不保证接收方收到的数据块和发送方发送的数据块具有对应大小关系,例如,发送方应用程序交给发送方的 TCP10 个数据块,接收方的 TCP 可能只用收到的 4 个数据块字节流交付给上层的应用程序

TCP 的可靠性原理

可靠传输有如下两个特点:

  1. 传输信道无差错,保证传输数据正确;
  2. 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据;

首先,采用三次握手来建立 TCP 连接,四次握手来释放 TCP 连接,从而保证建立的传输信道是可靠的。

其次,TCP 采用了连续 ARQ 协议(回退 N(Go-back-N);超时自动重传)来保证数据传输的正确性,使用滑动窗口协议来保证接方能够及时处理所接收到的数据,进行流量控制。

最后,TCP 使用慢开始、拥塞避免、快重传和快恢复来进行拥塞控制,避免网络拥塞。

报文段

TCP 虽面向字节流,但传送的数据单元为报文段

报文段 = 首部 + 数据 2 部分

TCP 的全部功能体现在它首部中各字段的作用

  1. 首部前 20 个字符固定、后面有 4n 个字节是根据需而增加的选项
  2. 故 TCP 首部最小长度 = 20 字节

端口

源端口号和目地端口各占 16 位两个字节,也就是端口的范围是2^16=65535

另外 1024 以下是系统保留的,从 1024-65535 是用户使用的端口范围

seq 序号:占 4 字节,TCP 连接中传送的字节流中的每个字节都按顺序编号。

例如:一段报文的序号字段值是 107,携带的数据是 100 个字段,下一个报文段序号从 107+100=207 开始。

ack 确认号:4 个字节,是期望收到对方下一个报文段的第一个数据字节的序号。

例如:B 收到 A 发送的报文,其序号字段是 301,数据长度是 200 字节,表明 B 正确收到 A 发送的到序号 500 为止的数据(301+200-1=500),B 期望收到 A 下一个数据序号是 501,B 发送给 A 的确认报文段中把 ack 确认号置为 501。

数据偏移:头部有可选字段,长度不固定,指出 TCP 报文段的数据起始处距离报文段的起始处有多远。

保留:保留今后使用的,被标为 1。

控制位:由 8 个标志位组成。每个标志位表示一个控制功能。

其中主要的 6 个:

  • URG 紧急指针标志,为 1 表示紧急指针有效,为 0 忽略紧急指针。

  • ACK 确认序号标志,为 1 表示确认号有效,为 0 表示报文不含确认信息,忽略确认号字段,上面的确认号是否有效就是通过该标识控制的。

  • PSH 标志,为 1 表示带有 push 标志的数据,指示接收方在接收到该报文段以后,应尽快将该报文段交给应用程序,而不是在缓冲区排队。

  • RST 重置连接标志,重置因为主机崩溃或其他原因而出现错误的连接,或用于拒绝非法的报文段或非法的连接。

  • SYN 同步序号,同步序号,用于建立连接过程,在连接请求中,SYN=1 和 ACK=0 表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即 SYN=1 和 ACK=1。。

  • FIN 终止标志,用于释放连接,为 1 时表示发送方没有发送了。

窗口:滑动窗口大小,用来告知发送端接收端缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。

校验和:奇偶校验,此校验和是对整个的 TCP 报文段(包括 TCP 头部和 TCP 数据),以 16 位进行计算所得,由发送端计算和存储,接收端进行验证。

紧急指针:只有控制位中的 URG 为 1 时才有效,指出本报文段中的紧急数据的字节数。

选项:其长度可变,定义其他的可选参数。

粘包与拆包

TCP 是面向字节流的协议,把上层应用层的数据看成字节流,所以它发送的不是固定大小的数据包,TCP 协议也没有字段说明发送数据包的大小。

而且 TCP 不保证接受方应用程序收到的数据块和发送应用程序发送的数据块具有对应的大小关系

比如发送方应用程序交给发送方TCP 10 个数据块,接受方 TCP 可能只用了 4 个数据块就完整的把接受到的字节流交给了上层应用程序。

TCP 底层并不了解上层业务数据的具体含义,它会根据 TCP 缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被 TCP 拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的 TCP 粘包和拆包问题

TCP 粘包/拆包解决策略

由于 TCP 无法理解上一层的业务数据特点,所以 TCP 是无法保证发送的数据包不发生粘包和拆包,这个问题只能通过上层的协议栈设计来解决,解决思路有一下几种:

  • 消息定长:每个发送的数据包大小固定,比如 100 字节,不足 100 字节的用空格补充,接受方取数据的时候根据这个长度来读取数据

  • 消息末尾增加换行符来表示一条完整的消息:接收方读取的时候根据换行符来判断是否是一条完整的消息,如果消息的内容也包含换行符,那么这种方式就不合适了。

  • 将消息分为消息头和消息尾两部分,消息头指定数据长度,根据消息长度来读取完整的消息,例如 UDP 协议是这么设计的,用两个字节来表示消息长度,所以 UDP 不存在粘包和拆包问题。

三次握手

第一次握手

客户端将 TCP 报文标志位SYN置为 1,随机产生一个序号值seq=J,保存在 TCP 首部的序列号字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT状态,等待服务器端确认。

第二次握手

服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将 TCP 报文标志位 SYN 和 ACK 都置为 1,ack=J+1,随机产生一个序号值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。

第三次握手

客户端收到确认后,检查 ack 是否为J+1,ACK 是否为 1,如果正确则将标志位 ACK 置为 1,ack=K+1,并将该数据包发送给服务器端,服务器端检查 ack 是否为K+1,ACK 是否为 1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

上面写的 ack 和 ACK,不是同一个概念:

  • 小写的 ack 代表的是头部的确认号 Acknowledge number, 缩写 ack,是对上一个包的序号进行确认的号,ack=seq+1

  • 大写的 ACK,则是我们上面说的 TCP 首部的标志位,用于标志的 TCP 包是否对上一个包进行了确认操作,如果确认了,则把 ACK 标志位设置成 1。

TCP 为什么三次握手而不是两次握手

  • 为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤

  • 如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认

《计算机网络》中是这样说的:

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

在书中同时举了一个例子,如下:

假如client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server,本来这是一个早已失效的报文段,但server收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。

于是就向 client 发出确认报文段,同意建立连接,假设不采用三次握手,那么只要 server 发出确认,新的连接就建立了,由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。

但 server 却以为新的连接已经建立,并一直等待client发来数据,这样,server 的很多资源就白白浪费掉了。

采用三次握手的办法可以防止上述现象发生,例如刚才那种情况,client 不会向server的确认发出确认,server 由于收不到确认,就知道 client 并没有要求建立连接。

什么是半连接队列

服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列

当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

补充一点关于SYN-ACK 重传次数的问题:

服务器发送完 SYN-ACK 包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。

三次握手过程中可以携带数据吗

其实第三次握手的时候,是可以携带数据的,也就是说,第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。

假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。也就是说,第一次握手可以放数据的话,其中一个简单的原因就是会让服务器更加容易受到攻击了。

而对于第三次的话,此时客户端已经处于 established 状态,也就是说,对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据没啥毛病。

四次挥手

挥手请求可以是 Client 端,也可以是 Server 端发起的,我们假设是 Client 端发起:

  • 第一次挥手: Client 端发起挥手请求,向 Server 端发送标志位是 FIN 报文段,设置序列号 seq,此时,Client 端进入FIN_WAIT_1状态,这表示 Client 端没有数据要发送给 Server 端了。

  • 第二次挥手:Server 端收到了 Client 端发送的 FIN 报文段,向 Client 端返回一个标志位是 ACK 的报文段,ack 设为 seq 加 1,Client 端进入FIN_WAIT_2状态,Server 端告诉 Client 端,我确认并同意你的关闭请求。

  • 第三次挥手: Server 端向 Client 端发送标志位是 FIN 的报文段,请求关闭连接,同时 Client 端进入LAST_ACK状态。

  • 第四次挥手 : Client 端收到 Server 端发送的 FIN 报文段,向 Server 端发送标志位是 ACK 的报文段,然后 Client 端进入TIME_WAIT状态,Server 端收到 Client 端的 ACK 报文段以后,就关闭连接,此时,Client 端等待 2MSL 的时间后依然没有收到回复,则证明 Server 端已正常关闭,那好,Client 端也可以关闭连接了。

为什么连接的时候是三次握手,关闭的时候却是四次握手?

建立连接时因为当 Server 端收到 Client 端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。所以建立连接只需要三次握手。

由于 TCP 协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP 是全双工模式。

这就意味着,关闭连接时,当 Client 端发出 FIN 报文段时,只是表示 Client 端告诉 Server 端数据已经发送完毕了。当 Server 端收到 FIN 报文并返回 ACK 报文段,表示它已经知道 Client 端没有数据发送了,但是 Server 端还是可以发送数据到 Client 端的,所以 Server 很可能并不会立即关闭 SOCKET,直到 Server 端把数据也发送完毕。

当 Server 端也发送了 FIN 报文段时,这个时候就表示 Server 端也没有数据要发送了,就会告诉 Client 端,我也没有数据要发送了,之后彼此就会愉快的中断这次 TCP 连接。

为什么 TIME_WAIT 要等待 2MSL?

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。

有以下两个原因:

  • 第一点:保证 TCP 协议的全双工连接能够可靠关闭: 由于 IP 协议的不可靠性或者是其它网络原因,导致了 Server 端没有收到 Client 端的 ACK 报文,那么 Server 端就会在超时之后重新发送 FIN,如果此时 Client 端的连接已经关闭处于CLOESD状态,那么重发的 FIN 就找不到对应的连接了,从而导致连接错乱,所以,Client 端发送完最后的 ACK 不能直接进入CLOSED状态,而要保持TIME_WAIT,当再次收到 FIN 的时候,能够保证对方收到 ACK,最后正确关闭连接。
  • 第二点:保证这次连接的重复数据段从网络中消失 如果 Client 端发送最后的 ACK 直接进入CLOSED状态,然后又再向 Server 端发起一个新连接,这时不能保证新连接的与刚关闭的连接的端口号是不同的,也就是新连接和老连接的端口号可能一样了,那么就可能出现问题:如果前一次的连接某些数据滞留在网络中,这些延迟数据在建立新连接后到达 Client 端,由于新老连接的端口号和 IP 都一样,TCP 协议就认为延迟数据是属于新连接的,新连接就会接收到脏数据,这样就会导致数据包混乱,所以 TCP 连接需要在TIME_WAIT状态等待 2 倍 MSL,才能保证本次连接的所有数据在网络中消失。

流量控制

RTT 和 RTO

RTT:发送一个数据包到收到对应的 ACK,所花费的时间

RTO:重传时间间隔(TCP 在发送一个数据包后会启动一个重传定时器,RTO 即定时器的重传时间)

开始预先算一个定时器时间,如果回复 ACK,重传定时器就自动失效,即不需要重传;如果没有回复 ACK,RTO 定时器时间就到了,重传。

RTO 是本次发送当前数据包所预估的超时时间,RTO 不是固定写死的配置,是经过 RTT 计算出来的。

滑动窗口

TCP 的滑动窗口主要有两个作用:

  1. 保证 TCP 的可靠性

  2. 保证 TCP 的流控特性

TCP 报文头有个字段叫 Window,用于接收方通知发送方自己还有多少缓存区可以接收数据,发送方根据接收方的处理能力来发送数据,不会导致接收方处理不过来,这便是流量控制。

发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。

发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。

不同的滑动窗口协议窗口大小一般不同。

发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧

滑动窗口由四部分组成每个字节的数据都有唯一顺序的编码,随着时间发展,未确认部分与可以发送数据包编码部分向右移动,形式滑动窗口

  1. 绿色:发送成功并已经 ACK 确认的数据
  2. 黄色:发送成功等待 ACK 确认的数据(占用滑动窗口大小)
  3. 紫色:滑动窗口剩余大小可以发送的字节数量(滑动窗口可用大小)
  4. 灰色:后续数据编码

接收窗口的大小就是滑动窗口的最大值,数据传输过程中滑动窗口的可用大小是动态变化的。

但是还有这么一点,滑动窗口的设计仅仅是考虑到了处理方的处理能力,但是没有考虑到道路的通畅问题

就好像服务端可以处理 100M 数据,但是传输的数据 99M 都堵在路上了,这不就是导致道路阻塞了么?这就需要另外一个设计拥塞避免

流量控制的目的

如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失。

为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。

流量控制根本目的是防止分组丢失,它是构成 TCP 可靠性的一方面。

如何实现流量控制

由滑动窗口协议(连续 ARQ 协议)实现。滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。

主要的方式就是接收方返回的 ACK 中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送。

流量控制引发的死锁

当发送者收到了一个窗口为 0 的应答,发送者便停止发送,等待接收者的下一个应答。

但是如果这个窗口不为 0 的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁。

为了避免流量控制引发的死锁,TCP 使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为 0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。

拥塞控制

为什么要进行拥塞控制

假设网络已经出现拥塞,如果不处理拥塞,那么延时增加,出现更多丢包,触发发送方重传数据,加剧拥塞情况,继续恶性循环直至网络瘫痪。

拥塞控制与流量控制的适应场景和目的均不同。

拥塞发生前,可避免流量过快增长拖垮网络;拥塞发生时,唯一的选择就是降低流量。

主要使用 4 种算法完成拥塞控制:

  1. 慢启动
  2. 拥塞避免
  3. 快重传算法
  4. 快速恢复算法

算法 1、2 适用于拥塞发生前,算法 3 适用于拥塞发生时,算法 4 适用于拥塞解决后(相当于拥塞发生前)。

rwnd 与 cwnd

rwnd(Receiver Window,接收者窗口)与cwnd(Congestion Window,拥塞窗口):

  • rwnd 是用于流量控制的窗口大小,主要取决于接收方的处理速度,由接收方通知发送方被动调整。

  • cwnd 是用于拥塞处理的窗口大小,取决于网络状况,由发送方探查网络主动调整。

同时考虑流量控制与拥塞处理,则发送方窗口的大小不超过min{rwnd, cwnd}

慢启动算法

慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。

这里用报文段的个数作为拥塞窗口的大小举例说明慢开始算法,实际的拥塞窗口大小是以字节为单位的。

一个传输轮次所经历的时间其实就是往返时间 RTT,而且每经过一个传输轮次,拥塞窗口 cwnd 就加倍。

为了防止 cwnd 增长过大引起网络拥塞,还需设置一个慢开始门限 ssthresh 状态变量。

ssthresh 的用法如下:

  • cwnd<ssthresh 时,使用慢开始算法。

  • 当 cwnd>ssthresh 时,改用拥塞避免算法。

  • 当 cwnd=ssthresh 时,慢开始与拥塞避免算法任意

注意,这里的慢并不是指 cwnd 的增长速率慢,而是指在 TCP 开始发送报文段时先设置 cwnd=1,然后逐渐增大,这当然比按照大的 cwnd 一下子把许多报文段突然注入到网络中要慢得多。

拥塞避免算法

让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是加倍。

这样拥塞窗口 cwnd 按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多

无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有按时收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限 ssthresh 设置为出现拥塞时的发送窗口大小的一半(但不能小于 2)。

然后把拥塞窗口 cwnd 重新设置为 1,执行慢开始算法。

这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

整个拥塞控制的流程:

假定 cwnd=24 时,网络出现超时(拥塞),则更新后的 ssthresh=12,cwnd 重新设置为 1,并执行慢开始算法。

当 cwnd=12=ssthresh 时,改为执行拥塞避免算法

注意:拥塞避免并非完全能够避免了阻塞,而是使网络比较不容易出现拥塞。

快重传算法

快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方,可提高网络吞吐量约 20%)而不要等到自己发送数据时捎带确认。

快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期

快恢复算法

快重传配合使用的还有快恢复算法,有以下两个要点:

  • 当发送方连续收到三个重复确认时,就把 ssthresh 门限减半(为了预防网络发生拥塞)。

  • 但是接下去并不执行慢开始算法

考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。

所以此时不执行慢开始算法,而是将 cwnd 设置为 ssthresh 减半后的值,然后执行拥塞避免算法,使 cwnd 缓慢增大。

Socket

即套接字,是应用层 与 TCP/IP 协议族通信的中间软件抽象层,表现为一个封装了 TCP / IP 协议族 的编程接口(API)

Socket不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)

对用户来说,只需调用 Socket 去组织数据,以符合指定的协议,即可通信

UDP

UDP 协议特点

  • UDP 是无连接的传输层协议;

  • UDP 使用尽最大努力交付,不保证可靠交付;

  • UDP 是面向报文的,对应用层交下来的报文,不合并,不拆分,保留原报文的边界;

  • UDP 没有拥塞控制,因此即使网络出现拥塞也不会降低发送速率;

  • UDP 支持一对一 一对多 多对多的交互通信;

  • UDP 的首部开销小,只有8字节

TCP 和 UDP 的区别

  • TCP 是可靠传输,UDP 是不可靠传输;

  • TCP 面向连接,UDP 无连接;

  • TCP 传输数据有序,UDP 不保证数据的有序性;

  • TCP 不保存数据边界,UDP 保留数据边界;

  • TCP 传输速度相对 UDP 较慢;

  • TCP 有流量控制和拥塞控制,UDP 没有;

  • TCP 是重量级协议,UDP 是轻量级协议;

  • TCP 首部较长 20 字节,UDP 首部较短8字节;

基于 TCP 和 UDP 的常用协议

HTTP、HTTPS、FTP、TELNET、SMTP(简单邮件传输协议)协议基于可靠的 TCP 协议。

TFTP、DNS、DHCP、TFTP、SNMP(简单网络管理协议)、RIP 基于不可靠的 UDP 协议

报文段

UDP 的报文段共有 2 个字段:数据字段 + 首部字段

UDP 报文中每个字段的含义如下:

  • 源端口:这个字段占据 UDP 报文头的前 16 位,通常包含发送数据报的应用程序所使用的 UDP 端口,接收端的应用程序利用这个字段的值作为发送响应的目的地址,这个字段是可选的,所以发送端的应用程序不一定会把自己的端口号写入该字段中,如果不写入端口号,则把这个字段设置为 0,这样,接收端的应用程序就不能发送响应了。
  • 目的端口:接收端计算机上 UDP 软件使用的端口,占据 16 位。
  • 长度:该字段占据 16 位,表示 UDP 数据报长度,包含 UDP 报文头和 UDP 数据长度,因为 UDP 报文头长度是 8 个字节,所以这个值最小为 8。
  • 校验值:该字段占据 16 位,可以检验数据在传输过程中是否被损坏。

网络层

MAC 地址

MAC 称为物理地址,也叫硬件地址,用来定义网络设备的位置,MAC 地址是网卡出厂时设定的,是固定的(但可以通过在设备管理器中或注册表等方式修改,同一网段内的 MAC 地址必须唯一)。

MAC 地址采用十六进制数表示,长度是 6 个字节(48 位),分为前 24 位和后 24 位。

MAC 地址对应于 OSI 参考模型的第二层数据链路层,工作在数据链路层的交换机维护着计算机 MAC 地址和自身端口的数据库,交换机根据收到的数据帧中的目的 MAC 地址字段来转发数据帧。

IP 地址

常见的 IP 地址分为 IPv4 与 IPv6 两大类,当前广泛应用的是 IPv4,目前 IPv4 几乎耗尽,下一阶段必然会进行版本升级到 IPv6;

IP 地址是以网络号和主机号来标示网络上的主机的,我们把网络号相同的主机称之为本地网络,网络号不相同的主机称之为远程网络主机

本地网络中的主机可以直接相互通信;远程网络中的主机要相互通信必须通过本地网关(Gateway)来传递转发数据。

IP 地址对应于 OSI 参考模型的第三层网络层,工作在网络层的路由器根据目标 IP 和源 IP 来判断是否属于同一网段,如果是不同网段,则转发数据包。

IP 地址格式和表示

IP 地址(IPv4)由 32 位二进制数组成,分为 4 段(4 个字节),每一段为 8 位二进制数(1 个字节)

每一段 8 位二进制,中间使用英文的标点符号.隔开

由于二进制数太长,为了便于记忆和识别,把每一段 8 位二进制数转成十进制,大小为 0 至 255。

IP 地址的这种表示法叫做点分十进制表示法

IP 地址表示为:xxx.xxx.xxx.xxx

举个栗子:210.21.196.6就是一个 IP 地址的表示。

计算机的 IP 地址由两部分组成,一部分为网络标识,一部分为主机标识,同一网段内的计算机网络部分相同,主机部分不能同时重复出现。

路由器连接不同网段,负责不同网段之间的数据转发,交换机连接的是同一网段的计算机。

通过设置网络地址和主机地址,在互相连接的整个网络中保证每台主机的 IP 地址不会互相重叠,即 IP 地址具有了唯一性。

IP 地址分类详解

IP 地址分 A、B、C、D、E 五类,其中 A、B、C 这三类是比较常用的 IP 地址,D、E 类为特殊地址。

子网掩码

子网掩码的概念及作用

通过子网掩码,才能表明一台主机所在的子网与其他子网的关系,使网络正常工作。

子网掩码和 IP 地址做与运算,分离出 IP 地址中的网络地址和主机地址,用于判断该 IP 地址是在本地网络上,还是在远程网络网上。

子网掩码还用于将网络进一步划分为若干子网,以避免主机过多而拥堵或过少而 IP 浪费。

子网掩码的组成

同 IP 地址一样,子网掩码是由长度为 32 位二进制数组成的一个地址。

子网掩码 32 位与 IP 地址 32 位相对应,IP 地址如果某位是网络地址,则子网掩码为 1,否则为 0。

举个栗子:如:11111111.11111111.11111111.00000000

左边连续的 1 的个数代表网络号的长度,(使用时必须是连续的,理论上也可以不连续),右边连续的 0 的个数代表主机号的长度。

为什么要使用子网掩码

两台主机要通信,首先要判断是否处于同一网段,即网络地址是否相同。

如果相同,那么可以把数据包直接发送到目标主机,否则就需要路由网关将数据包转发送到目的地。

可以这么简单的理解:A 主机要与 B 主机通信,A 和 B 各自的 IP 地址与 A 主机的子网掩码进行 And 与运算,看得出的结果:

1、结果如果相同,则说明这两台主机是处于同一个网段,这样 A 可以通过 ARP 广播发现 B 的 MAC 地址,B 也可以发现 A 的 MAC 地址来实现正常通信。

2、如果结果不同,ARP 广播会在本地网关终结,这时候 A 会把发给 B 的数据包先发给本地网关,网关再根据 B 主机的 IP 地址来查询路由表,再将数据包继续传递转发,最终送达到目的地 B。


计算机的网关(Gateway)就是到其他网段的出口,也就是路由器接口 IP 地址。

路由器接口使用的 IP 地址可以是本网段中任何一个地址,不过通常使用该网段的第一个可用的地址或最后一个可用的地址,这是为了尽可能避免和本网段中的主机地址冲突。

在如下拓扑图示例中,A 与 B,C 与 D,都可以直接相互通信(都是属于各自同一网段,不用经过路由器)

但是 A 与 C,A 与 D,B 与 C,B 与 D 它们之间不属于同一网段,所以它们通信是要经过本地网关,然后路由器根据对方 IP 地址,在路由表中查找恰好有匹配到对方 IP 地址的直连路由,于是从另一边网关接口转发出去实现互连

子网掩码和 IP 地址的关系

子网掩码是用来判断任意两台主机的 IP 地址是否属于同一网络的依据

拿双方主机的 IP 地址和自己主机的子网掩码做与运算,如结果为同一网络,就可以直接通信

如何根据 IP 地址和子网掩码,计算网络地址:

将 IP 地址与子网掩码转换成二进制数。

将二进制形式的 IP 地址与子网掩码做与运算。

将得出的结果转化为十进制,便得到网络地址。

网关

网关实质上是一个网络通向其他网络的 IP 地址。

比如有网络 A 和网络 B,网络 A 的 IP 地址范围为192.168.1.1~192. 168.1.254,子网掩码为255.255.255.0

网络 B 的 IP 地址范围为192.168.2.1~192.168.2.254,子网掩码为255.255.255.0

在没有路由器的情况下,两个网络之间是不能进行 TCP/IP 通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP 协议也会根据子网掩码(255.255.255.0)判定两个网络中的主机处在不同的网络里。

而要实现这两个网络之间的通信,则必须通过网关。

如果网络 A 中的主机发现数据包的目的主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发给网络 B 的网关,网络 B 的网关再转发给网络 B 的某个主机。网络 B 向网络 A 转发数据包的过程。

所以说,只有设置好网关的 IP 地址,TCP/IP 协议才能实现不同网络之间的相互通信。

那么这个 IP 地址是哪台机器的 IP 地址呢?

网关的 IP 地址是具有路由功能的设备的 IP 地址,具有路由功能的设备有路由器、启用了路由协议的服务器(实质上相当于一台路由器)、代理服务器(也相当于一台路由器)。

linux中0.0.0.0代表局域网网关,不用经过路由就可以直接转发

Ping

Ping 是我们测试网络连接的常用指令。

它利用 ICMP 报文检测网络连接。

假设 A ping B

  1. ping 通知系统建立一个固定格式的 ICMP 请求数据包。

  2. ICMP 协议打包这个数据包和 B 的 IP 地址转交给 IP 协议层

  3. IP 层协议将机器 B 的 IP 地址为目的地址,本机的 IP 地址为源地址,加上一些头部必要的控制信息,构建一个 IP 数据包

  4. 获取 B 的 MAC 地址,做这个操作首先机器 A 会判断 B 是否在同一网段内,若 IP 层协议通过 B 的 IP 地址和自己的子网掩码,发现它跟自己属于同一网络,就直接在本网络查找这台机器的 MAC,否则则通过路由器进行类似查找。

接下来是 ARP 协议根据 IP 地址查找 MAC 地址的过程:

  • 若两台机器之前有过通信,在机器 A 的 ARP 缓存表里应该存有 B 的 IP 与其 MAC 地址的映射关系。

  • 若没有,则通过发送 ARP 请求广播,得到回应的 B 机器 MAC 地址,并交给数据链路层

  1. 数据链路层构建一个数据帧,目的地址是 IP 层传过来的 MAC 地址,源地址是本机的 MAC 地址,再附加一些必要的控制信息,依据以太网的介质访问规则将他们传送出去

  2. 机器 B 收到这个数据帧后,先检查目的地址,和本机 MAC 地址对比:

符合,接受,接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的的 IP 地址协议层协议,IP 协议层检查之后,将有用的信息提取给 ICMP 协议,后者处理,马上构建一个 ICMP 应答包,发送给 A,其过程和主机 A 发送 ICMP 请求包到 B 的过程类似,但不用 ARP 广播收取 A 的信息,因为请求包中已经有足够的信息用于 B 回应 A。

若不符合,丢弃。

可以知道 PING 的过程即一段发送报文和接受确认报文的过程,在来回直接可以计算时延。

DNS

DNS 通过主机名,最终得到该主机名对应的 IP 地址的过程叫做域名解析(或主机名解析)。

通俗的讲,我们更习惯于记住一个网站的名字,www.baidu.comopen in new window,而不是记住它的ip地址,比如:167.23.10.2

工作原理

将主机域名转换为 ip 地址,属于应用层协议,使用 UDP 传输。

第一步,客户端向本地 DNS 服务器发送解析请求

第二步,本地 DNS 如有相应记录会直接返回结果给客户端,如没有就向 DNS 根服务器发送请求

第三步,DSN 根服务器接收到请求,返回给本地服务器一个所查询域的主域名服务器的地址

第四步,本地 dns 服务器再向返回的主域名服务器地址发送查询请求

第五步,主域名服务器如有记录就返回结果,没有的话返回相关的下级域名服务器地址

第六步,本地 DNS 服务器继续向接收到的地址进行查询请求

第七步,下级域名服务器有相应记录,返回结果

第八步,本地 dns 服务器将收到的返回地址发给客户端,同时写入自己的缓存,以便下次查询

DNS 域名查询实际上就是个不断递归查询的过程,直到查找到相应结果,需要注意的时,当找不到相应记录,会返回空结果,而不是超时信息

DNS 记录

A 记录

定义www.example.com的ip地址
www.example.com.     IN     A     139.18.28.5;

上面的就是一条 DNS 记录,纯文本即可。

www.example.com 是要解析的域名。

A 是记录的类型,A 记录代表着这是一条用于解析 IPv4 地址的记录。

从这条记录可知,www.example.com的 IP 地址是 139.18.28.5。

CNAME

CNAME 用于定义域名的别名,如下面这条 DNS 记录:

定义www.example.com的别名
a.example.com.          IN     CNAME   b.example.com.

这条 DNS 记录定义了 a.example.comb.example.com 的别名。

用户在浏览器中输入 a.example.com 时候,通过 DNS 查询会知道 a.example.comb.example.com 的别名,因此需要实际 IP 的时候,会去拿 b.example.com 的 A 记录。

当你想把一个网站迁移到新域名,旧域名仍然保留的时候;还有当你想将自己的静态资源放到 CDN 上的时候,CNAME 就非常有用。

AAAA 记录

A 记录是域名和 IPv4 地址的映射关系。和 A 记录类似,AAAA 记录则是域名和 IPv6 地址的映射关系。

MX 记录

MX 记录是邮件记录,用来描述邮件服务器的域名。

在工作中,我们经常会发邮件到某个同事的邮箱。

比如说,发送一封邮件到 xiaoming@xiaoflyfish.com,那么如何知道哪个 IP 地址是邮件服务器呢?

这个时候就可以用到下面这条 MX 记录:

IN MX mail.xiaoflyfish.com

mail.xiaoflyfish.com 的 IP 地址可以通过查询 mail.xiaoflyfishcom 的 A 记录和 AAAA 记录获得。

NS 记录

NS 记录是描述 DNS 服务器网址。从 DNS 的存储结构上说,Name Server 中含有权威 DNS 服务的目录。

也就是说,NS 记录指定哪台 Server 是回答 DNS 查询的权威域名服务器。

当一个 DNS 查询看到 NS 记录的时候,会再去 NS 记录配置的 DNS 服务器查询,得到最终的记录。如下面这个例子:

a.com.     IN      NS      ns1.a.com.
a.com.     IN      NS      ns2.a.com.

当解析 a.com 地址时,我们看到 a.com 有两个 NS 记录,所以确定最终 a.com 的记录在 ns1.a.comns2.a.com 上。

从设计上看,ns1 和 ns2 是网站 a.com 提供的智能 DNS 服务器,可以提供负载均衡、分布式 Sharding 等服务。

比如当一个北京的用户想要访问 a.com 的时候,ns1 看到这是一个北京的 IP 就返回一个离北京最近的机房 IP。

上面代码中 a.com 配置了两个 NS 记录。

通常 NS 不会只有一个,这是为了保证高可用,一个挂了另一个还能继续服务。

通常数字小的 NS 记录优先级更高,也就是 ns1 会优先于 ns2 响应。

配置了上面的 NS 记录后,如果还配置了 a.com 的 A 记录,那么这个 A 记录会被 NS 记录覆盖。

ARP 协议

ARP 即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标 IP 对应的 MAC 地址。

ARP 协议的工作过程

首先,每个主机都会有自己的 ARP 缓存区中建立一个 ARP 列表,以表示 IP 地址和 MAC 地址之间的对应关系

当源主机要发送数据时,首先检测 ARP 列表中是否对应 IP 地址的目的主机的 MAC 地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送 ARP 数据包

当本网络的所有主机收到该 ARP 数据包时,首先检查数据包中的 IP 地址是否是自己的 IP 地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的 IP 和 MAC 地址写入到 ARP 列表中,如果存在,则覆盖然后将自己的 MAC 地址写入 ARP 响应包中,告诉源主机自己是它想要找的 MAC 地址

源主机收到 ARP 响应包后,将目的主机的 IP 和 MAC 地址写入 ARP 列表,并利用此信息发送数据,如果源主机一直没有收到 ARP 响应数据包,表示 ARP 查询失败。

数字签名

网络传输过程中需要经过很多中间节点,虽然数据无法被解密,但可能被篡改

数字签名校验数据的完整性

数字签名有两种功效

  • 能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名。

  • 数字签名能确定消息的完整性,证明数据是否未被篡改过。

将一段文本先用 Hash 函数生成消息摘要,然后用发送者的私钥加密生成数字签名,与原文文一起传送给接收者

接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用 HASH 函数对收到的原文产生一个摘要信息,与上一步得到的摘要信息对比。

如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。

SQL 注入

SQL 注入的原理是将 SQL 代码伪装到输入参数中,传递到服务器解析并执行的一种攻击手法。

SQL 注入攻击实例

比如,在一个登录界面,要求输入用户名和密码,可以这样输入实现免帐号登录:

用户名: ‘or 1 = 1 --
密 码:

用户一旦点击登录,如若没有做特殊处理,那么这个非法用户就很得意的登陆进去了。

下面我们分析一下:从理论上说,后台认证程序中会有如下的 SQL 语句:

String sql =select * from user_table where username=’ “+userName+” ’ and password=’ “+password+” ‘”;

因此,当输入了上面的用户名和密码,上面的 SQL 语句变成:

SELECT * FROM user_table WHERE username=’’or 1 = 1- and password=’’

分析上述 SQL 语句我们知道,username=‘ or 1=1 这个语句一定会成功;然后后面加两个 -,这意味着注释,它将后面的语句注释,让他们不起作用,这样,上述语句永远都能正确执行,用户轻易骗过系统,获取合法身份。

应对方法

预编译

使用预编译手段,绑定参数是最好的防 SQL 注入的方法。

目前许多的 ORM 框架及 JDBC 等都实现了 SQL 预编译和参数绑定功能,攻击者的恶意 SQL 会被当做 SQL 的参数而不是 SQL 命令被执行。

在 mybatis 的 mapper 文件中,对于传递的参数我们一般是使用 ## 和$来获取参数值。

当使用#时,变量是占位符,就是一般我们使用 java 的 jdbc 的 PrepareStatement 时的占位符,所有可以防止 sql 注入;

当使用$时,变量就是直接追加在 sql 中,一般会有 sql 注入问题。

使用正则表达式过滤传入的参数

过滤参数中含有的一些数据库关键词

加密算法

加密算法分对称加密非对称加密,其中对称加密算法的加密与解密密钥相同,非对称加密算法的加密密钥与解密密钥不同,此外,还有一类不需要密钥的散列算法

常见的 对称加密 算法主要有 DES3DESAES 等,常见的 非对称算法 主要有 RSADSA 等,散列算法 主要有 SHA-1MD5 等。

对称加密

对称加密算法 中,使用的密钥只有一个,发送和接收双方都使用这个密钥对数据进行 加密解密

  • 数据加密过程:在对称加密算法中,数据发送方 将 明文 (原始数据) 和 加密密钥 一起经过特殊 加密处理,生成复杂的 加密密文 进行发送。

  • 数据解密过程:数据接收方 收到密文后,若想读取原数据,则需要使用 加密使用的密钥 及相同算法的 逆算法 对加密的密文进行解密,才能使其恢复成 可读明文

非对称加密

非对称加密算法,它需要两个密钥,一个称为 公开密钥 (public key),即 公钥,另一个称为 私有密钥 (private key),即 私钥

因为 加密解密 使用的是两个不同的密钥,所以这种算法称为 非对称加密算法

  1. 如果使用 公钥 对数据 进行加密,只有用对应的 私钥 才能 进行解密

  2. 如果使用 私钥 对数据 进行加密,只有用对应的 公钥 才能 进行解密

例子:甲方生成 一对密钥 并将其中的一把作为 公钥 向其它人公开,得到该公钥的 乙方 使用该密钥对机密信息 进行加密 后再发送给甲方,甲方再使用自己保存的另一把 专用密钥 (私钥),对 加密 后的信息 进行解密

网络攻击

CSRF 和 XSS

XSS:

跨站脚本是一种网站应用程序的安全漏洞攻击,是代码注入的一种。

它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响,这类攻击通常包含了 HTML 以及用户端脚本语言。

比如通过客户端脚本语言(最常见如:JavaScript)

在一个论坛发帖中发布一段恶意的 JavaScript 代码就是脚本注入,如果这个代码内容有请求外部服务器,那么就叫做 XSS

XSS 攻击分类

反射性 XSS 攻击 (非持久性 XSS 攻击)

例如,正常发送消息:

http://www.test.com/message.php?send=Hello,World!

接收者将会接收信息并显示 HelloWorld;但是,非正常发送消息:

http://www.test.com/message.php?send=<script>alert(‘foolish!’)</script>!

接收者接收消息显示的时候将会弹出警告窗口!

持久性 XSS 攻击 (留言板场景)

一般指 XSS 攻击代码存储在网站数据库,当一个页面被用户打开的时候执行。

也就是说,每当用户使用浏览器打开指定页面时,脚本便执行。

与非持久性 XSS 攻击相比,持久性 XSS 攻击危害性更大。

从名字就可以了解到,持久性 XSS 攻击就是将攻击代码存入数据库中,然后客户端打开时就执行这些攻击代码。

例如,留言板表单中的表单域:

<input type="text" name="content" value="这里是用户填写的数据">

正常操作流程是:用户是提交相应留言信息 — 将数据存储到数据库 — 其他用户访问留言板,应用去数据并显示;

而非正常操作流程是攻击者在 value 填写:

<script>alert(‘foolish!’);</script> <!--或者html其他标签(破坏样式。。。)、一段攻击型代码-->

并将数据提交、存储到数据库中;当其他用户取出数据显示的时候,将会执行这些攻击性代码

CSRF:

跨站请求伪造,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。

比如冒充用户发起请求(在用户不知情的情况下),完成一些违背用户意愿的请求(如恶意发帖,删帖,改密码,发邮件等)。

DOS 攻击

DOS:中文名称是拒绝服务,该攻击的效果是使得计算机或网络无法提供正常的服务

DOS 攻击的原理:

首先攻击者向被攻击的服务器发送大量的虚假 IP 请求,被攻击者在收到请求后返回确认信息,等待攻击者进行确认,该过程需要 TCP 的三次握手,由于攻击者发送的请求信息是虚假的,所以服务器接收不到返回的确认信息,在一段时间内服务器会处与等待状态,而分配给这次请求的资源却被有被释放

当被攻击者等待一定的时间后,会因连接超时而断开,这时攻击者在次发送新的虚假信息请求,这样最终服务器资源被耗尽,直到瘫痪

DDOS:中文名称是分布式拒绝服务攻击

指的是攻击者控制多台主机同时向同一主机或网络发起DOS攻击

DRDoS 分布反射式拒绝服务攻击这是DDoS攻击的变形

DDOS 究竟如何攻击

目前最流行也是最好用的攻击方法就是使用SYN-Flood进行攻击,SYN-Flood 也就是 SYN 洪水攻击

SYN-Flood 不会完成 TCP 三次握手的第三步,也就是不发送确认连接的信息给服务器,这样,服务器无法完成第三次握手,但服务器不会立即放弃,服务器会不停的重试并等待一定的时间后放弃这个未完成的连接,这段时间叫做SYN timeout,这段时间大约 30 秒-2 分钟左右。

若是一个用户在连接时出现问题导致服务器的一个线程等待 1 分钟并不是什么大不了的问题,但是若有人用特殊的软件大量模拟这种情况,那后果就可想而知了。一个服务器若是处理这些大量的半连接信息而消耗大量的系统资源和网络带宽,这样服务器就不会再有空余去处理普通用户的正常请求(因为客户的正常请求比率很小),这样这个服务器就无法工作了,这种攻击就叫做SYN-Flood攻击

到目前为止,进行 DDoS 攻击的防御还是比较困难的

首先,这种攻击的特点是它利用了 TCP/IP 协议的漏洞,除非你不用 TCP/IP,才有可能完全抵御住 DDoS 攻击

不过这不等于我们就没有办法阻挡 DDoS 攻击,我们可以尽力来减少 DDoS 的攻击

下面就是一些防御方法:

  1. 关闭不必要的服务

  2. 限制同时打开的 SYN 半连接数目

  3. 缩短 SYN 半连接的 time out 时间

  4. 正确设置防火墙

  5. 禁止对主机的非开放服务的访问

  6. 限制特定 IP 地址的访问

  7. 启用防火墙的防 DDoS 的属性

Session 是基于 Cookie 实现的另一种记录服务端和客户端会话状态的机制。

Session 是存储在服务端,而 SessionId 会被存储在客户端的 Cookie 中。

Session 的认证过程

  1. 客户端第一次发送请求到服务端,服务端根据信息创建对应的 Session,并在响应头返回 SessionID
  2. 客户端接收到服务端返回的 SessionID 后,会将此信息存储在 Cookie 上,同时会记录这个 SessionID 属于哪个域名
  3. 当客户端再次访问服务端时,请求会自动判断该域名下是否存在 Cookie 信息,如果有则发送给服务端,服务端会从 Cookie 中拿到 SessionID,再根据 SessionID 找到对应的 Session,如果有对应的 Session 则通过,继续执行请求,否则就中断

Cookie 和 Session 的区别

  1. 安全性,因为 Cookie 可以通过客户端修改,而 Session 只能在服务端设置,所以安全性比 Cookie 高,一般会用于验证用户登录状态
  2. 适用性,Cookie 只能存储字符串数据,而 Session 可以存储任意类型数据
  3. 有效期,Cookie 可以设置任意时间有效,而 Session 一般失效时间短

常见面试题

在浏览器地址栏键入 URL

1.DNS 解析:浏览器会依据 URL 逐层查询 DNS 服务器缓存,解析 URL 中的域名对应的 IP 地址,DNS 缓存从近到远依次是浏览器缓存、系统缓存、路由器缓存、IPS 服务器缓存、域名服务器缓存、顶级域名服务器缓存。

从哪个缓存找到对应的 IP 直接返回,不再查询后面的缓存。

2.TCP 连接:结合三次握手

3.发送 HTTP 请求:浏览器发出读取文件的 HTTP 请求,该请求发送给服务器

4.服务器处理请求并返回 HTTP 报文:服务器对浏览器请求做出响应,把对应的带有 HTML 文本的 HTTP 响应报文发送给浏览器

5.浏览器解析渲染页面

6.连接结束:浏览器释放 TCP 连接,该步骤即四次挥手。

第 5 步和第 6 步可以认为是同时发生的,哪一步在前没有特别的要求


作者:月伴飞鱼,转载链接:https://mp.weixin.qq.com/s/7EddtzpwIRvYfw34QE4zvwopen in new window