(二)Nodejs网络详解

848 阅读28分钟

参考资料:

  1. http协商缓存VS强缓存
  2. 彻底弄懂强缓存与协商缓存
  3. http和https的区别

一、网络模型

1、OSI七层模型

  • 第7层应用层:为操作系统或网络应用程序提供访问网络服务的接口。
    • 协议包括:https、http、ftp、telnet、ssh、smtp、pops、dns等
    • html
  • 第6层表示层:把数据转换为接受者能够兼容并且传输的内容,比如数据加密、压缩、格式转换等。
  • 第5层会话层:负责数据传输中设置和维持网络设置直接的通讯连接。管理主机之间的会话进程,还可以利用在数据中插入校验点来实现数据同步。
  • 第4层传输层:把传输表头加至数据形成数据包,完成端到端的数据传输,传输表头包含协议等信息。
    • 协议包括:tcp、udp协议
  • 第3层网络层:负责对子网间的数据包进行寻址和路由选择,还可以实现阻塞控制和网际互联等功能。
    • 协议包括:ip、ipx等
    • 路由器
  • 第2层数据链路层:在物理介质上提供可靠的传输,包括物理地址寻址、数据封装成帧、流量控制、数据校验、重发等
    • 交互机
  • 第1层物理层:在局域网传输数据帧,负责电脑通讯设备和网络媒体之间的互通,包括针脚、电压、线缆规范、集线器、网卡、主机适配。

2、TCP/IP参考模型

TCP/IP参考模型是⼀个抽象的分层模型,这个模型中,所有的TCP/IP系列⽹络协议都归类到4 个抽象的“层”中:

  • 应用层:应用层、表示层、会话层
  • 传输层:传输层
  • 网络层:网络层
  • 链路层:数据链路层、物理层

二、TCP和UDP协议

1、区别

传输层协议:

  • UDP是⽆连接的,TCP必须三次握⼿建⽴连接;
  • UDP是⾯向报⽂,没有拥塞控制,所以速度快,适合多媒体通信要求,⽐如及时聊天,⽀持⼀对⼀,⼀对多,多对⼀,多对多。就像⽜客⽹的视频⾯试就是⽤的UDP;
  • TCP只能是⼀对⼀的可靠性传输。

2、TCP协议

1、可靠性保证
  • 超时重发,发出报文端要是没有收到及时的确认,会重发
  • 数据包的校验,校验首部数据和
  • 对失序的数据重新排序
  • 进行流量控制,防止缓冲区溢出
  • 快重传和会恢复
  • TCP会将数据截断为合理的长度
2、TCP如何提供可靠性
  • 超时重发,发出报⽂段要是没有收到及时的确认,会重发。
  • 数据包的校验,也就是校验⾸部数据。
  • 对失序的数据重新排序
  • 进⾏流量控制,防⽌缓冲区溢出
  • 快重传和快恢复
  • TCP会将数据截断为合理的⻓度
3、TCP如何控制拥塞

拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。

发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量和慢开始门限ssthresh状态变量:初始设置ssthresh=16,cwnd=1.

  • 当cwnd<ssthresh时,使⽤慢开始算法,也就是乘法算法,拥塞窗口 cwnd 随着传输次数按指数规律增长。
  • 当cwnd=ssthresh时,慢开始与拥塞避免算法任意。
  • 当cwnd>ssthresh时,改⽤拥塞避免算法,也就是加法算法,拥塞窗口按线性规律增长。
  • 当出现拥塞的时候就把新的门限值ssthresh设为此时窗口大小cwnd的一半,窗口大小设置为1,再重新执行上面的步骤。eg:cwnd为24时拥堵,设置ssthresh为12,cwnd为1,再开始慢开始算法。
  • 当收到连续三个重传的时候这就需要快重传和快恢复了,当收到连续三个重传,这个时候发送方就要重传自己的信息,然后门限ssthresh减半,但是这个时候并不是网络阻塞,窗口cwnd只会减半,执行拥塞避免算法。
4、三次握手、四次挥手

TCP协议的一次数据传输, 从建立连接到断开连接都有哪些流程?

  • 三次握手

    • 第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
    • 第二次握手:服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
    • 第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。完成了三次握手,客户端和服务器端就可以开始传送数据。
  • 四次挥手

    • 第一次挥手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
    • 第二次挥手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;
    • 第三次挥手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
    • 第四次挥手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

3、IP地址

网络层协议

  • IP 地址(IPv4 地址)由32位正整数来表示,在计算机内部以二进制方式被处理
    • 将32位的 IP 地址以每8位为一组,分成4组,每组以 “.” 隔开,再将每组数转换成十进制数(0-255)。
    • IP地址包含网络标识和主机标识,eg:172.112.110.11,172.112.110就是网络标识,,同一网段内网络标识必须相同。11就是主机标识,,同一网段内主机标识不能重复。
  • IPv6:解决 IPv4 地址耗尽的问题而被标准化的网际协议。IPv4 的地址长度为 4 个 8 位字节,即 32 比特,而 IPv6 的地址长度则是原来的 4 倍,即 128 比特,一般写成 8 个 16 位字节。通常写成8组,每组为四个十六进制数的形式。比如:AD80:0000:0000:0000:ABAA:0000:00C2:0002

4、DNS

应用层协议:DNS协议是用来将域名转换为IP地址(也可以将IP地址转换为相应的域名地址)

  • DNS使用TCP和UDP端口53。
  • 对于每一级域名长度的限制是63个字符,域名总长度则不能超过253个字符。

客户端发送查询报文"query zh.wikipedia.org"至DNS服务器:(以访问 zh.wikipedia.org 为例)

  • DNS服务器首先检查自身缓存,如果存在记录则直接返回结果。如果记录老化或不存在,则执行如下步骤:
  • DNS服务器向根域名服务器发送查询报文"query zh.wikipedia.org",根域名服务器返回顶级域 .org 的顶级域名服务器地址。
  • DNS服务器向 .org 域的顶级域名服务器发送查询报文"query zh.wikipedia.org",得到二级域 .wikipedia.org 的权威域名服务器地址。
  • DNS服务器向 .wikipedia.org 域的权威域名服务器发送查询报文"query zh.wikipedia.org",得到主机 zh 的A记录,存入自身缓存并返回给客户端。

5、HTTP

HTTP协议(HyperText Transfer Protocol,超⽂本传输协议)是⽤于从WWW服务器传输超⽂本到本地浏览器的传输协议。HTTP是客户端浏览器或其他程序与Web服务器之间的应⽤层通信协议。在Internet上的Web服务器上存放的都是超⽂本信息,客户机需要通过HTTP协议传输所要访问的超⽂本信息。

1、URI和URL
  • URI:uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
  • URL:Uniform Resource Locator,统⼀资源定位符,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源,常用URL标识每个⽹⻚Internet地址。
2、完整的http通讯
  • 建⽴ TCP 连接,⼀般 TCP 连接的端⼝号是80
  • 客户端向服务器发送请求命令,如GET/info.html HTTP/1.1
  • 客户端发送请求头信息,如user-agent,host等关于自身的信息,最后发送空⽩⾏来通知服务器,它已经结束了该头信息的发送;若为post请求,会继续发送请求体。
  • 服务器应答,响应的第⼀部分是协议的版本号和响应状态码,例如: HTTP/1.1 200 OK
  • 服务器返回响应头信息,关于⾃身的信息及被请求的⽂档;
  • 服务器向客户端发送数据:发送头信息后,它会发送⼀个空⽩⾏来表示头信息的发送到此为结束,接着它就以 Content-Type 响应头信息所描述的格式发送⽤户所请求的实际数据;
  • 服务器关闭 TCP 连接:⼀般情况下,⼀旦服务器向客户端返回了请求数据,它就要关闭 TCP 连接,然后如果客户端或者服务器在其头信息加⼊了这⾏代码 Connection:keep-alive ,TCP 连接在发送后将仍然保持打开状态,于是,客户端可以继续通过相同的连接发送请求。保持连接节省了为每个请求建⽴新连接所需的时间,还节约了⽹络带宽。
3、HTTP协议特点
  • 通过请求和响应的交换达成通信:协议规定, 请求从客户端发出, 服务端响应请求并返回。

  • 无状态:协议对于发送过的请求或响应都不做持久化处理

  • 使用Cookie做状态管理:服务端返回的头信息上有可能会携带Set-Cookie, 那么当客户端接收到响应后, 就会在本地种上cookie. 在下一次给服务端发送请求的时候, 就会携带上这些cookie。

  • 通过URL定位资源

  • 方法标识意图:比如GET POST PUT DELETE等

  • 持久连接:HTTP 协议的初始版本中,每进行一个 HTTP 通信都要断开一次 TCP 连接,增加了很多没必要的建立连接的开销。为了解决上述 TCP 连接的问题,HTTP/1.1 支持持久连接。其特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。旨在建立一次 TCP 连接后进行多次请求和响应的交互。在 HTTP/1.1 中,所有的连接默认都是持久连接,也就是说默认情况下建立 TCP 连接不会断开,只有在请求报头中声明 Connection: close 才会在请求完成后关闭连接。

  • 管道机制:1.1版本引入pipelining机制, 即在同一个TCP连接里面,客户端可以同时发送多个请求。

    举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。但是现代浏览器一般没开启这个配置, 这个机制可能会造成队头阻塞. 因为响应是有顺序的, 如果一个TCP连接中的第一个HTTP请求响应非常慢, 那么就会阻塞后续HTTP请求的响应,所以现实中默认情况下, 一个TCP连接同一时间只发一个HTTP请求.

4、HTTP1.0/1.1/2.0
1、并发强求区别
  • HTTP1.0:每次TCP连接只能发送一个请求,当服务器响应后就会关闭这次连接,下一个请求需要再次建立TCP连接.

  • HTTP1.1:

    • 默认采用持续连接(TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive);
    • 增加了管道机制,在同一个TCP连接里,允许多个请求同时发送,增加了并发性,进一步改善了HTTP协议的效率,但是同一个TCP连接里,所有的数据通信是按次序进行的。回应慢,会有许多请求排队,造成"队头堵塞"。
  • HTTP2.0

    • 加了双工模式,即不仅客户端能够同时发送多个请求,服务端也能同时处理多个请求,解决了队头堵塞的问题。
    • 使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
    • 增加服务器推送的功能,不经请求服务端主动向客户端发送数据。
2、其他问题
  1. HTTP1.1⻓连接和HTTP2.0多路复⽤的区别?

    • HTTP1.1:同⼀时间⼀个TCP连接只能处理⼀个请求, 采⽤⼀问⼀答的形式, 上⼀个请求响应后才能处理下⼀个请求. 由于浏览器最⼤TCP连接数的限制, 所以有了最⼤并发请求数的限制。
    • HTTP2.0:同域名下所有通信都在单个连接上完成,消除了因多个 TCP 连接⽽带来的延时和内存消耗。单个连接上可以并⾏交错的请求和响应,之间互不⼲扰。
  2. 为什么HTTP/1.1不能实现多路复⽤?

    HTTP2是基于⼆进制“帧”的协议,HTTP1.1是基于“⽂本分割”解析的协议

    • HTTP1.1的报⽂结构中, 服务器需要不断的读⼊字节,直到遇到换⾏符或者说⼀个空⽩⾏。处理顺序是串⾏的,⼀个请求和⼀个响应需要通过⼀问⼀答的形式才能对应起来。
    • HTTP2.0中,有两个⾮常重要的概念,分别是帧(frame)和流(stream)。帧代表着最⼩的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。多路复⽤,就是在⼀个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极⼤的提⾼传输性能。
5、HTTP状态码
  • 1xx: 信息性状态码,webscoket
  • 2xx: 成功状态码,200、204(No Content) 、206(范围请求,⽐如⾳视频资源)
  • 3xx: 重定向, 301(永久) 、302(临时,可能会改变方法) 、304(协商缓存)、 307(临时,不会从post变为get) 、308(永久)
  • 4xx: 客户端错误, 400(bad request) 、401(Unauthorized,无session,未登录认证) 、403(Forbidden) 、404(not found) 、405(Method not allowed)
  • 5xx: 服务端错误,500(Internal server error) 、502(Bad Gateway) 、503(Service Unavailable)
6、HTTP请求头
1、Connection

请求头和返回头

  • close:HTTP/1.1 版本的默认连接都是持久连接。当服务器端想明确断开连接时,则指定Connection⾸部字段的值为 close
  • Keep-Alive:HTTP/1.1 之前的HTTP版本的默认连接都是⾮持久连接。为此,如果想在旧版本的HTTP协议上维持持续连接,则需要指定Connection⾸部字段的值为Keep-Alive。
2、Allow

返回头:⽤于通知客户端能够⽀持 Request-URI 指定资源的所有 HTTP ⽅法。

当服务器接收到不⽀持的 HTTP ⽅法时,会以状态码 405 Method Not Allowed 作为响应返回。与此同时,还会把所有能⽀持的 HTTP ⽅法写⼊⾸部字段 Allow 后返回。Allow: GET, HEAD。

3、Host

请求头,Host: aam.sdc.cs.icbc:11688

  • 告知服务器,请求的资源所处的互联⽹主机和端⼝号。
  • Host ⾸部字段是 HTTP/1.1 规范内唯⼀⼀个必须被包含在请求内的⾸部字段。
  • 若服务器未设定主机名,那直接发送⼀个空值即可 Host: 。
4、Accept、Accept-Language、Accept-Encoding

请求头

  • Accept: text/html, application/xhtml+xml, application/xml;

    Accept ⾸部字段可通知服务器,⽤户代理能够处理的媒体类型及媒体类型的相对优先级。可使⽤ type/subtype 这种形式,⼀次指定多种媒体类型。

  • Accept-Encoding: gzip, deflate

    Accept-Encoding ⾸部字段⽤来告知服务器⽤户代理⽀持的内容编码及内容编码的优先顺序,并可⼀次性指定多种内容编码,也可使⽤星号(*)作为通配符,指定任意的编码格式。

    • gzip表明实体采⽤GNU zip编码
    • compress表明实体采⽤Unix的⽂件压缩程序
    • deflate表明实体采⽤zlib的格式压缩的
    • identity表明没有对实体进⾏编码,当没有 Content-Encoding ⾸部字段时,默认采⽤此编码⽅式
  • Accept-Language: zh-cn,zh;q=0.5

    表示浏览器所支持的语言类型,浏览器支持的语言分别是简体中文和中文,优先支持简体中文。

5、Content-Encoding、Content-Type、Content-language

响应头

  • Content-Encoding: gzip

    告知客户端服务器对实体的主体部分选⽤的内容编码⽅式。内容编码是指在不丢失实体信息的前提下所进⾏的压缩。

  • Content-Type: text/html; charset=UTF-8

    说明了实体主体内对象的媒体类型。和⾸部字段 Accept ⼀样,字段值⽤ type/subtype 形式赋值。

  • Content-language:zh-cn,zh;q=0.5

    说明了实体主体内对象的语言类型

6、User-Agent

请求头

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36

⾸部字段 User-Agent 会将创建请求的浏览器和⽤户代理名称等信息传达给服务器。由⽹络爬⾍发起请求时,有可能会在字段内添加爬⾍作者的电⼦邮件地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称。

7、Set-Cookie、Cookie

Set-Cookie返回头、Cookie请求头

Set-Cookie: userId=11111; expires=Mon, 10 Jul 20121 15:50:06 GMT; path=/;

  • NAME=VALUE: cookie名称和值
  • expires=DATE: Cookie 的有效期(若不明确指定则默认为浏览器关闭前为⽌)
  • path=PATH: ⽤于限制指定 Cookie 的发送范围的⽂件⽬录。
  • domain=域名: cookie有效的域名 (若不指定则默认为创建 Cookie的服务器的域名)
  • Secure: 仅在 HTTPS 安全通信时才会发送 Cookie
  • HttpOnly: 使 Cookie 不能被 JavaScript 脚本访问
8、强缓存:Expires、Cache-Control
  • Expires:返回头,这是http1.0时的规范,Expires: Mon, 10 Jul 2021 15:50:06 GMT

    • ⾸部字段 Expires 会将资源失效的⽇期告知客户端。
    • 缓存服务器在接收到含有⾸部字段 Expires 的响应后,会以缓存来应答请求,在 Expires 字段值指定的时间之前,响应的副本会⼀直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。
  • Cache-Control:返回头,设置缓存机制

    • Cache-Control: public,可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器
    • Cache-Control: private,只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存
    • Cache-Control: no-cache,可以在客户端存储资源,每次都必须去服务端做过期校验,来决定从服务端获取新的资源

    (200)还是使⽤客户端缓存(304)。也就是所谓的协商缓存。

    • Cache-Control: no-store,永远都不要在客户端存储资源,永远都去原始服务器去获取资源。
    • Cache-Control: max-age=604800(单位:秒),当客户端发送的请求中包含 max-age 指令时,如果判定缓存资源的缓存时间数值⽐指定的时间更⼩,那么客户端就接收缓存的资源。另外,当指定 max-age 的值为0,那么缓存服务器通常需要将请求转发给源服务器。HTTP/1.1 版本的缓存服务器遇到同时存在 Expires ⾸部字段的情况时,会优先处理max-age指令,并忽略Expires ⾸部字段
    • Cache-Control: s-maxage=604800(单位:秒),s-maxage 指令的功能和 max-age 指令的相同,它们的不同点是 s-maxage 指令只适⽤于供多位⽤户使⽤的公共缓存服务器(⼀般指代理)。当使⽤ s-maxage 指令后,则直接忽略对 Expires ⾸部字段及 max-age 指令的处理
9、协商缓存:ETag、If-None-Match、Last-Modified、If-Modified-Since
  • If-Modified-Since: Mon, 10 Jul 2021 15:50:06 GMT,请求头。

    • ⽤于确认代理或客户端拥有的本地资源的有效性。
    • 在指定 If-Modified-Since 字段值的⽇期时间之后,如果请求的资源都没有过更新,则返回状态码 304 Not Modified 的响应
  • If-None-Match: “lubai”,请求头。⽤于指定 If-None-Match 字段值的实体标记(ETag)值与请求资源的 ETag 不⼀致时,它就告

    知服务器处理该请求。

  • ETag: “aaaa-1234”,返回头,⾸部字段 ETag 能告知客户端实体标识。它是⼀种可将资源以字符串形式做唯⼀性标识的⽅式。服务器会为每份资源分配对应的 ETag 值。另外,当资源更新时,ETag 值也需要更新。⽣成 ETag 值时,并没有统⼀的算法规则,⽽仅仅是由服务器来分配。

  • Last-Modified : Fri , 12 May 2006 18:53:33 GMT,返回头。在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。

//1、强缓存响应头设置:浏览器直接读取内存或硬盘,不发起请求
//两个条件:不是当前页面的第一个请求(非浏览器url地址栏的请求)、在有效期内
res.setHeader('Cache-Control','max-age=10'); //单位s,相对时间,http1.1,比expires优先
res.setHeader('Expires',new Date(Date.now() + 10*1000).toUTCString()); //绝对时间,Date.now()返回ms

//2、协商缓存
//服务器返回Last-Modified(改变时间)、Etag(文件内容hash值)
//浏览器下次请求时返回:If-None-Match、If-Modified-Since

//3、实践,返回强缓存、协商缓存头
const img = fs.readFileSync('./ip_kinds.jpg')
const etag = crypto.createHash('md5').update(img).digest('base64')
const reqEtag = req.headers['if-none-match']
// 有etag就根据etag判断,返回304还是200
if(reqEtag && reqEtag == etag) {
 console.log('etag 协商缓存⽣效')
 res.statusCode = 304
 res.end()
 return;
}
const imgStat = fs.statSync('./ip_kinds.jpg')
const ctime = imgStat.ctime.toUTCString();
const reqLastModified = req.headers['if-modified-since']
// 没有etag根据last-modified 判断304还是200
if(reqLastModified === ctime) {
 console.log('last modified 协商缓存⽣效')
 res.statusCode = 304
 res.end()
 return;
}
// 200 -> 读⽂件,设置强缓存和协商缓存
// 强缓存——响应头
res.setHeader('Cache-Control','max-age=10');
res.setHeader('Expires',new Date(Date.now() + 10*1000).toUTCString());
// 协商缓存——响应头
res.setHeader('Last-Modified', ctime);
res.setHeader('Etag',etag );
res.end(img)
7、HTTPS
1、https握手

http + ssl/tsl = https,其中ssl/tsl协议为http和tcp之间的协议,在osi7层模型的会话层和表示层、保证了传输过程的安全性

特点:

  1. 内容加密:采用混合加密技术,中间者无法直接查看明文
  2. 验证身份:通过证书认证客户端访问的是自己的服务器
  3. 保护数据完整性:防止传输的内容背中间人冒充或者篡改

握手过程:

  • 客户端发起https请求,端口443,发送随机数1和客户端支持的加密算法;
  • 服务端收到信息后回传响应信息,包括随机数2和匹配的加密算法;
  • 服务端配置数字证书,实质为公私钥,其中数字证书为认证机构处理过的公钥,包含:证书颁发机构、过期时间、服务端公钥、第三方证书认证机构CA的签名、服务端的域名信息等内容。
  • 服务端传输数字证书给客户端;
  • 客户端解析证书并验证,有问题提示警告,无问题生成随机值3,将随机数1、随机数2、随机值3组合成密钥,并用公钥加密;
  • 客户端向服务端传输加密后的对称密钥;
  • 服务端接收后,用私钥解密出对称密钥,拿对称密钥对传输内容进行对称加密;
  • 服务端传输加密后的报文;
  • 客户端用随机值进行解密,获取报文。
2、证书校验

数字证书内容:包括了加密后服务器的公钥、权威机构的信息、服务器域名,还有经过CA私钥签名之后的证书内容(先通过Hash函数计算得到证书数字摘要,然后用权威机构私钥加密数字摘要得到数字签名),签名计算方法以及证书对应的域名

https握手过程中,客户端如何验证证书的合法性:

  1. 首先浏览器读取证书中的证书所有者、有效期等信息进行校验:校验证书的网站域名是否与证书颁发域名一致,校验证书是否在有效期内;
  2. 浏览器开始查找操作系统中已内置的受信任的证书颁发机构CA,与服务器发来的证书中的颁发者CA进行对比,用于校验证书是否为合法机构颁发;
  3. 如果找不到,浏览器会报错,说明浏览器发来的证书是不可信任的;
  4. 如果找到,那么浏览器会从操作系统中取出颁发者CA的公钥(浏览器一般内置常用认证机构的公钥),然后对服务器发来的证书里的数字签名进行解密;
  5. 浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算值与证书中签名做对比;
  6. 对比结果一致,证明服务器发来的证书合法,没有被冒充
3、中间人攻击

https中间人攻击:

  1. 服务器向客户端发送公钥;
  2. 攻击者截获公钥,保留在自己手上;
  3. 攻击者伪造假公钥,发给客户端;
  4. 客户端收到伪造的假公钥,生成加密hash值发给服务器;
  5. 攻击者获得加密hash值,用自己私钥解密获取hash值,同时生成假的hash加密值,发给服务器;
  6. 服务器用私钥解密获得假的hash值,用假的hash值加密传输信息。

防范:服务器在发送浏览器的公钥中加入ca证书,浏览器可以验证ca证书的有效性(现有https很难被劫持,除非信任了劫持者的ca证书)

6、Nodejs网络模块

  • socket套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用,来实现进程在网络中通信,比如create,listen,accept,connect,read和write等等。
  • http为应用层模块,主要按照特定协议编解码数据;
  • net为传输层模块,主要负责传输编码后的应用层数据;
  • https是个综合模块(涵盖了http/tls/crypto等),主要用于确保数据安全性
1、TCP模块
  • tcp客户端
const net = require('net');

const HOST = '127.0.0.1';
const PORT = 7777;

// 创建一个TCP服务器实例,调用listen函数开始监听指定端口
// net.createServer()有一个参数, 是监听连接建立的回调
net.createServer((socket) => {
    const remoteName = `${socket.remoteAddress}:${socket.remotePort}`;
    // 建立成功了一个连接, 这个回调函数里返回一个socket对象.
    console.log(`${remoteName} 连接到本服务器`);

    // 接收消息
    socket.on('data', (data) => {
        console.log(`${remoteName} - ${data}`)
        // 给客户端发消息
        socket.write(`你刚才说啥?是${data}吗?`);
    });

    // 关闭
    socket.on('close', (data) => {
        console.log(`${remoteName} 连接关闭`)
    });

}).listen(PORT, HOST);

console.log(`Server listening on ${HOST}:${PORT}`);
  • tcp服务端
const net = require('net');
const HOST = '127.0.0.1';
const PORT = 7777;
const client = new net.Socket();
const ServerName = `${HOST}:${PORT}`;
let count = 0;
client.connect(PORT, HOST, () => {
 console.log(`成功连接到 ${ServerName}`);
// 向服务端发送数据
const timer = setInterval(() => {
if (count > 10) {
 client.write('我没事了, 告辞');
clearInterval(timer);
return; }
 client.write('⻢冬梅' + count++);
}, 1000)
});
// 接收消息
client.on('data', (data) => {
 console.log(`${ServerName} - ${data}`);
// 关闭连接
// client.destroy();
});
// 关闭事件
client.on('close', () => {
 console.log('Connection closed');
});
client.on('error', (error) => {
 console.log(error);
})
2、UDP模块
  • server
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('message', (msg, remote) => {
 console.log(`${remote.address}:${remote.port} - ${msg}`)
 server.send(`收到!`, remote.port, remote.address);
})
server.on('listening', () => {
const address = server.address()
 console.log(`Server listening on ${address.address}:${address.port}`);
})
server.bind(44444);
  • client
const dgram = require('dgram')
const message = Buffer.alloc(5, 'lubai')
const client = dgram.createSocket('udp4')
client.send(message, 0, message.length, 44444, 'localhost', (err, bytes) => {
 console.log(`发送成功${bytes}字节`);
// client.close()
} )
client.on('message', (buffer) => {
 console.log(buffer.toString())
})
3、HTTP模块
//server
const http = require('http')
http.createServer(function (req, res) {
 res.writeHead(200, {
'Content-Type': 'text/plain'
})
 res.end('Hello World')
}).listen(80, '127.0.0.1')
console.log('Server running at http://127.0.0.1:80/')

//client
const http = require('http')
const options = {
 hostname: '127.0.0.1',
 port: 80,
 path: '/',
 method: 'GET'
}
const req = http.request(options, (res) => {
 console.log(`Status=${res.statusCode}, Headers=$ {JSON.stringify(res.headers)}`);
 res.setEncoding('utf8')
 res.on('data', (data) => {
 console.log(data)
})
})
req.end()
//浏览器访问:http://127.0.0.1:80/
//curl访问:curl -v http://127.0.0.1:80

// 三次握⼿
* Rebuilt URL to: http://127.0.0.1:80/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)

// 客户端向服务端发送请求报⽂
> GET / HTTP/1.1
> Host: 127.0.0.1:80
> User-Agent: curl/7.54.0
> Accept: */*
>

// 服务端响应客户端内容
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Wed, 04 Aug 2021 15:55:55 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
<
* Connection #0 to host 127.0.0.1 left intact
Hello World%
4、rpc调用

Remote Procedure Call(远程过程调⽤)

  • 与http调⽤的区别

    • 不⼀定使⽤ DNS 作为寻址服务,可使用内部协议存储

      • http传输时:test.com/aa -> ip
      • rpc传输时:可使用内部协议存储,v1://dd.ccc -> ip
    • 基于TCP或UDP协议

    • 使⽤⼆进制协议(更⼩的体积,更快的解码速率)

      • http传输时:明文一般为json格式
      • 使用二进制,eg:定义1-4位为name、5-9位为age,使用buffer库进行解析,也可使用protocol-buffers库进行处理,像使⽤JSON⼀样简单
  • tcp通信⽅式

    • 单⼯:只能由一方向另一方发送数据另一方不可以,客户端向服务端发送数据或服务端向客户端发送数据

    • 半双⼯:独木桥,双向都可发送数据,但每次只能传输一种数据,客户端向服务端发送数据后,服务端向客户端发送数据

    • 全双⼯:双方可同时发送数据

      • 错乱问题、粘包
      • 制定了⼀条协议规则,即 包序号(1-2字节)+ 包⻓度(3-6字节) + 包主体内容。

三、面试题

1、网络直播底层是什么协议?

分析:其实现在常⻅的rtmp(实时消息传输协议)和hls(HTTP Live Streaming)直播, 都是基于TCP的, 希望能提供稳定的直播环境.

2、为什么进行三次握手和四次挥手?

解析:

  1. 三次握手:为了解决“网络中存在延迟的重复分组”的问题(为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误),另一种描述,为了在不可靠信道上可靠地传输信息。
  2. 四次挥手:为实现TCP这种全双工连接的可靠释放;为使旧的数据包在网络因过期而消失

3、chrome最大支持6个同域名请求呢?

chrome最大支持同时开启6个TCP连接。

4、HTTP 协议和 HTTPS 区别?

  • http 是超文本传输协议,信息是明文传输,https 是具有安全性的 ssl 解密传输协议;
  • http 和 https 连接方式完全不同,端口也不同,http 是 80,https 是 443;
  • http 的连接很简单,是无状态的,https 协议是由 ssl+http 协议构建的可进行加密传输,身份认证的网络协议,比 http 协议安全。

5、http1.0、http1.1、http2.0的区别?

  1. 1和1.0相比,1.1可以一次传输多个文件
  2. http1.x解析基于文本,http2.0采用二进制格式,新增特性 多路复用、header压缩、服务端推送(静态html资源)

6、http如何实现缓存?

  1. 强缓存==>Expires(过期时间)/Cache-Control(no-cache)(优先级高) 协商缓存 ==>Last-Modified/Etag(优先级高)Etag适用于经常改变的小文件 Last-Modefied适用于不怎么经常改变的大文件
  2. 强缓存策略和协商缓存策略在缓存命中时都会直接使用本地的缓存副本,区别只在于协商缓存会向服务器发送一次请求。它们缓存不命中时,都会向服务器发送请求来获取资源。在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器直接使用本地资源的副本,如果协商缓存不命中,则浏览器返回最新的资源给浏览器。