一些网络方面的面试题

一、HTTP/HTTPS (⭐⭐⭐)

1、HTTP与HTTPS有什么区别?

HTTPS 是一种通过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。

HTTPS 和 HTTP 的概念:

HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 它是一个 URI scheme(抽象标识符体系),句法类同http:体系。用于安全的 HTTP 数据传输。https:URL 表明它使用了 HTTP,但 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP 与 TCP 之间)。这个系统的最初研发由网景公司进行,提供了身份验证与加密通讯方法,现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。

超文本传输协议 (HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

HTTPS 协议需要到 CA(Certificate Agent 证书机构)申请证书,一般免费证书很少,需要交费。

HTTP 和 HTTPS 用的端口也不一样,前者是80,后者是443。HTTP 的连接很简单,是无状态的, HTTPS 协议是由 SSL + HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全。

HTTPS 解决的问题:

  1. 信任主机的问题。采用 HTTPS 的 SERVER 必须从 CA 申请一个用于证明服务器用途类型的证书。改证书只有用于对应的 SERVER 的时候,客户度才信任次主机。
  2. 防止通讯过程中的数据的泄密和被篡改。

如下图所示,可以很明显的看出两个的区别:

HTTP & HTTPS

注:TLS是SSL的升级替代版,具体发展历史可以参考传输层安全性协议。

HTTP 与 HTTPS 在写法上的区别也是前缀的不同,客户端处理的方式也不同,具体说来:

  • 如果 URL的协议是HTTP,则客户端会打开一条到服务端端口80(默认)的连接,并向其发送老的HTTP请求。
  • 如果 URL的协议是HTTPS,则客户端会打开一条到服务端端口443(默认)的连接,然后与服务器握手,以二进制格式与服务器交换一些SSL的安全参数,附上加密的 HTTP请求。

所以你可以看到,HTTPS比HTTP多了一层与SSL的连接,这也就是客户端与服务端SSL握手的过程,整个过程主要完成以下工作:

  • 交换协议版本号
  • 选择一个两端都了解的密码
  • 对两端的身份进行认证
  • 生成临时的会话密钥,以便加密信道

SSL握手是一个相对比较复杂的过程,更多关于SSL握手的过程细节可以参考TLS/SSL握手过程

SSL/TSL的常见开源实现是OpenSSL,OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。更多源于OpenSSL的技术细节可以参考OpenSSL。

2、HTTP1.1和HTTP1.0及2.0的区别?

HTTP1.0和HTTP1.1的一些区别

HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 主要区别主要体现在:

  1. 缓存处理。 在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
  2. 带宽优化及网络连接的使用。 HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  3. 错误通知的管理。 在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
  4. Host头处理。 在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
  5. 长连接。 HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

SPDY

在讲HTTP1.1和HTTP2.0的区别之前,还需要说下SPDY,它是HTTP1.x的优化方案:

2012年Google如一声惊雷提出了SPDY的方案,优化了HTTP1.X的请求延迟,解决了HTTP1.X的安全性,具体如下:

  1. 降低延迟。 针对HTTP高延迟的问题,SPDY优雅的采取了多路复用(multiplexing)。多路复用通过多个请求stream共享一个 TCP 连接的方式,解决了HOL blocking的问题,降低了延迟同时提高了带宽的利用率。
  2. 请求优先级(request prioritization)。 多路复用带来一个新的问题是,在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY允许给每个request设置优先级,这样重要的请求就会优先得到响应。比如浏览器加载首页,首页的 HTML 内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第一时间看到网页内容。
  3. HEADER 压缩。 前面提到 HTTP1.x 的 HEADER 很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量。
  4. 基于 HTTPS 的加密协议传输。 大大提高了传输数据的可靠性。
  5. 服务端推送(server push)。 采用了 SPDY 的网页,例如我的网页有一个style.css的请求,在客户端收到style.css数据的同时,服务端会将style.js的文件推送给客户端,当客户端再次尝试获取style.js时就可以直接从缓存中获取到,不用再发请求了。

SPDY构成图:

SPDY设计模型

SPDY位于HTTP之下,TCP和SSL之上,这样可以轻松兼容老版本的HTTP协议(将HTTP1.x的内容封装成一种新的frame格式),同时可以使用已有的SSL功能。

但是在 HTTP2.0 推出之后,SPDY 就渐渐地退出历史舞台了。

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

  1. 新的二进制格式(Binary Format)。 HTTP1.x 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认01的组合。基于这种考虑 HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮。
  2. 多路复用(MultiPlexing)。 即连接共享,即每一个 request 都是是用作连接共享机制的。一个 request 应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面。
  3. HEADER 压缩。 如上文中所言,对前面提到过 HTTP1.x 的 HEADER 带有大量信息,而且每次都要重复发送,HTTP2.0 使用 encoder 来减少需要传输的 HEADER 大小,通讯双方各自缓存一份 HEADER FIELDS 表,既避免了重复 HEADER 的传输,又减小了需要传输的大小。
  4. 服务端推送(server push)。 同 SPDY 一样,HTTP2.0 也具有 server push 功能。

需要更深的理解请点击这里

3、HTTPS 请求慢的解决办法

1、不通过DNS解析,直接访问IP

经过 DNS 的解析,必然会增加一些时长,如果再出现诸如 DNS 污染等情况,则会直接导致无法访问到目标主机。

2、解决连接无法复用

HTTP1.0 协议头里可以设置Connection:Keep-Alive或者Connection:Close,选择是否允许在一定时间内复用连接(时间可由服务器控制)。但是这对 App 端的请求成效不大,因为 App 端的请求比较分散且时间跨度相对较大。

方案1. 基于tcp的长连接 (主要)

移动端建立一条自己的长链接通道,通道的实现是基于 TCP 协议。基于 TCP 的 Socket 编程技术难度相对复杂很多,而且需要自己定制协议。但信息的上报和推送变得更及时,请求量爆发的时间点还能减轻服务器压力(避免频繁创建和销毁连接)。

方案2. HTTP LONG-POLLING

客户端在初始状态发送一个 POLLING 请求到服务器,服务器并不会马上返回业务数据,而是等待有新的业务数据产生的时候再返回,所以链接会一直被保持。一但结束当前连接,马上又会发送一个新的 POLLING 请求,如此反复,保证一个连接被保持。

但这种方法也存在一些问题:

  1. 增加了服务器的压力
  2. 网络环境复杂场景下,需要考虑怎么重建健康的连接通道
  3. POLLING 的方式稳定性不好
  4. POLLING 的r esponse 可能会被中间代理缓存
方案3. HTTP Streaming

和 LONG-POLLING 不同的是,Streaming 方式通过在 server response 的头部增加Transfer Encoding:chuncked来告诉客户端后续还有新的数据到来。

它也存在问题:

  1. 有些代理服务器会等待服务器的 response 结束之后才将结果推送给请求客户端。Streaming 不会结束 response。
  2. 业务数据无法按照请求分割
方案4. WebSocket

和传统的 TCPSocket相似,基于 TCP 协议,提供双向的数据通道。它的优势是提供了 message 的概念,比基于字节流的TCPSocket使用更简单。技术较新,不是所有浏览器都提供了支持。

3、解决head of line blocking

它的原因是队列的第一个数据包(队头)受阻而导致整列数据包受阻。

使用http pipelining,确保几乎在同一时间把 request 发向了服务器

4、HTTP的request和response的协议组成

1、Request

客户端发送一个 HTTP 请求到服务器的请求消息格式:

请求行(request line)+ 请求头部(request header fields)+ 空行 + 请求数据(可选)。

如下例所示:

GET /test.jpg HTTP/1.1
Host: img.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept: image/webp,image/*,*/*;q=0.8
Referer: http://www.example.com/
Accept-Encoding: gzip, deflate, sdch

ts=1598909872

第一部分:请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本。请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本。常见的请求类型有GETPOSTPUTDELETEOPTIONSHEADTRACECONNECTPATCH等。
上例中的GET说明请求类型为GET,/test.jpg为要访问的资源,该行的最后一部分说明使用的是 HTTP1.1 版本。

第二部分:请求头部,紧接着请求行之后的部分,用来说明服务器要使用的附加信息。
从第二行起为请求头部,HOST 将指出请求的目的地。User-Agent,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础。该信息由你的浏览器来定义,并且在每个请求中自动发送。

第三部分:空行,请求头部后面的空行是必须的。空行只能包括<CR><LF>,并且不能有空格符。
即使第四部分的请求数据为空,也必须有空行。

第四部分:请求数据,也叫主体,可以添加任意的其他数据。

2、Response组成

一般情况下,服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息。

HTTP响应也由四个部分组成,分别是:

状态行(status line) + 消息报头(response header fields) + 空行 + 响应正文(可选)。

如下例所示:

HTTP/1.1 200 OK
Date: Mon, 23 May 2005 22:38:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 155
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
ETag: "3f80f-1b6-3e1cb03b"
Accept-Ranges: bytes
Connection: close

<html>
  <head>
    <title>An Example Page</title>
  </head>
  <body>
    <p>Hello World, this is a very simple HTML document.</p>
  </body>
</html>

第一部分:状态行,由 HTTP 协议版本号,状态码,状态消息三部分组成。
上例中第1行为状态行,HTTP/1.1表明 HTTP 版本为 1.1 版本,状态码为200,状态消息为OK

第二部分:消息报头,用来说明客户端要使用的一些附加信息。
上例中第2-9行为消息报头。如Content-Type指定了 MIME 类型的 HTMLtext/html,编码类型是UTF-8

第三部分:空行,消息报头后面的空行是必须的。空行只能包括<CR><LF>,并且不能有空格符。

第四部分:响应正文,服务器返回给客户端的文本信息。
上例中从第11行开始的部分为响应正文。

了解更多传送门

5、谈谈对 HTTP 缓存的了解

HTTP 的缓存机制也是依赖于 Request/Response Header Fields 里的参数来实现的,它决定最终响应是从缓存中取还是从服务端重新拉取,HTTP 的缓存机制的流程如下所示:

HTTP 缓存机制

HTTP 的缓存可以分为两种:

  • 强制缓存: 需要服务端参与判断是否继续使用缓存,当客户端第一次请求数据时,服务端返回了缓存的过期时间(Expires 与 Cache-Control),没有过期就可以继续使用缓存,否则则不适用,无需再向服务端询问。
  • 对比缓存: 需要服务端参与判断是否继续使用缓存,当客户端第一次请求数据时,服务端会将缓存标识(Last-Modified/If-Modified-Since 与 Etag/If-None-Match)与数据一起返回给客户端,客户端将两者都备份到缓存中,再次请求数据时,客户端将上次备份的缓存标识发送给服务端,服务端根据缓存标识进行判断,如果返回304,则表示通知客户端可以继续使用缓存。
    强制缓存优先于对比缓存。

上面提到强制缓存使用的的两个标识:

  • Expires: Expires 可以通俗地解释为缓存到期时间。即客户端首次请求时,服务端会记录下 Expires 值;客户端下一次请求时,如果请求时间小于服务端返回的到期时间,则直接使用缓存数据,否则使用服务端返回的数据。Expires 是服务端生成的,在使用时要注意客户端和服务端的时间误差。
  • Cache-Control: 由于上面的 Expires 有个时间校验的问题,所以在 HTTP1.1 中采用了 Cache-Control 替代 Expires。它的取值有以下几种:
    • private: 客户端可以缓存
    • public: 客户端和代理服务器都可缓存
    • max-age=xxx: 缓存的内容将在 xxx 秒后失效
    • no-cache: 需要使用对比缓存来验证缓存数据
    • no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发

我们再来看看对比缓存的两个标识 Last-Modified 和 If-Modified-Since:

Last-Modified 表示资源上次修改的时间。当客户端首次发送请求时,服务端返回资源上次修改的时间:

Last-Modified: Tue, 12 Jan 2016 09:31:27 GMT

客户端再次发送,会在 header fields 里携带If-Modified-Since。将上次服务端返回的资源时间上传给服务端。

If-Modified-Since: Tue, 12 Jan 2016 09:31:27 GMT

服务端接收到客户端发来的资源修改时间,与自己当前的资源修改时间进行对比,如果自己的资源修改时间大于客户端发来的资源修改时间,则说明资源做过修改, 则返回200表示需要重新请求资源,否则返回304表示资源没有被修改,可以继续使用缓存。

上面是一种时间戳标记资源是否修改的方法,还有一种资源标识码 ETag 的方式来标记是否修改,如果标识码发生改变,则说明资源已经被修改,ETag 优先级高于 Last-Modified

ETag 是资源文件的一种标识码,当客户端首次发送请求时,服务端会返回当前资源的标识码:

ETag: "5694c7ef-24dc"

客户端再次发送,会在 header fields 里携带上次服务端返回的资源标识码:

If-None-Match:"5694c7ef-24dc"

服务端接收到客户端发来的资源标识码,则会与自己当前的资源码进行比较,如果不同,则说明资源已经被修改,则返回200,如果相同则说明资源没有被修改,返回304,客户端可以继续使用缓存。

6、HTTP长连接。

HTTP1.0 是短连接,HTTP1.1 默认是长连接,也就是默认 Connection 的值就是keep-alive。但是长连接实质是指的 TCP 连接,而不是HTTP 连接,毕竟 HTTP 是应用层协议(第7层),TCP 是传输层协议(第4层)。TCP 连接是一个双向的通道,它是可以保持一段时间不关闭的,因此实际上我们常说的『HTTP 长连接』指的是『TCP 长连接』。

HTTP1.1 为什么要用使用 TCP 长连接?

TCP 长连接可以复用。即长连接情况下,多个 HTTP 请求可以复用同一个 TCP 连接,这就节省了很多 TCP 连接建立和断开的消耗。

此外,长连接并不是永久连接的。如果一段时间内(具体的时间长短,是可以在header当中进行设置的,也就是所谓的超时时间),这个连接没有HTTP 请求发出的话,那么这个长连接就会被断掉。

需要更深的理解请点击这里

7、HTTPS 加密原理。

加密算法的类型基本上分为了两种:

  • 对称加密。加密用的密钥和解密用的密钥是同一个,比较有代表性的就是 AES 加密算法;其它常见的还有 DES、RC4、RC5 等。
  • 非对称加密。加密用的密钥称为公钥,解密用的密钥称为私钥,经常使用到的 RSA 加密算法就是非对称加密的。

此外,还有Hash加密算法

HASH算法:MD5, SHA1, SHA256

相比较对称加密而言,非对称加密安全性更高,但是加解密耗费的时间更长,速度慢。

想了解更多加密算法请点击这里

HTTPS = HTTP + SSL,HTTPS 的加密就是在 SSL 层中完成的。

这就要从 CA 证书讲起了。CA 证书其实就是数字证书,是由 CA 机构颁发的。至于 CA 机构的权威性,那么是毋庸置疑的,所有人都是信任它的。CA 证书内一般会包含以下内容:

  • 证书的颁发机构、版本
  • 证书的使用者
  • 证书的公钥
  • 证书的有效时间
  • 证书的数字签名 Hash 值和签名 Hash 算法

客户端如何校验 CA 证书?

CA 证书中的 Hash 值,其实是用证书的私钥进行加密后的值(证书的私钥不在 CA 证书中)。然后客户端得到证书后,利用证书中的公钥去解密该 Hash 值,得到 Hash-a ;然后再利用证书内的签名 Hash 算法去生成一个 Hash-b 。最后比较 Hash-a 和 Hash-b 这两个的值。如果相等,那么证明了该证书是对的,服务端是可以被信任的;如果不相等,那么就说明该证书是错误的,可能被篡改了,浏览器会给出相关提示,无法建立起 HTTPS 连接。除此之外,还会校验 CA 证书的有效时间和域名匹配等。

HTTPS 中的 SSL 握手建立过程

假设现在有客户端 C 和服务器 S :

  1. 首先,C 访问 S ,比如我们用浏览器打开一个网页 www.baidu.com ,这时,浏览器就是 C ,百度的服务器就是 S 了。这时候 C 会生成一个随机数1,把随机数1、自己支持的 SSL 版本号以及支持的加密算法等这些信息告诉 S 。
  2. S 知道这些信息后,先确认一下双方的加密算法,再生成一个随机数2,并将随机数2和 CA 颁发给自己的证书一同返回给 C 。
  3. C 得到 CA 证书后,会去校验该 CA 证书的有效性(校验方法在上面说过),校验通过后,生成一个随机数3,然后用证书中的公钥加密随机数3并传输给 S 。
  4. S 得到加密后的随机数3,然后利用私钥进行解密,得到真正的随机数3
  5. 最后,C 和 S 都有随机数1、随机数2、随机数3,然后双方利用这三个随机数生成一个对话密钥。之后传输内容就是利用对话密钥来进行加解密了。这时就是利用了对称加密,一般用的都是 AES 算法。
  6. C 通知 S,指明后面的通讯用对话密钥来完成,同时通知 S 和 C 的握手过程结束。
  7. S 通知 C,指明后面的通讯用对话密钥来完成,同时通知 C 和 S 的握手过程结束。
  8. SSL 的握手部分结束,SSL 安全通道的数据通讯开始,C 和 S 开始使用相同的对话密钥进行数据通讯。

如下图所示:

SSL 握手过程

简化如下:

  1. 客户端和服务端建立 SSL 握手,客户端通过 CA 证书来确认服务端的身份;
  2. 互相传递三个随机数,之后通过这随机数来生成一个密钥;
  3. 互相确认密钥,然后握手结束;
  4. 数据通讯开始,都使用同一个对话密钥来加解密;

可以发现,在 HTTPS 加密原理的过程中把对称加密和非对称加密都利用了起来。即利用了非对称加密安全性高的特点,又利用了对称加密速度快,效率高的好处。

需要更深的理解请点击这里

8、HTTPS 如何防范中间人攻击?

什么是中间人攻击?

当数据传输发生在一个设备(PC/手机)和网络服务器之间时,攻击者使用其技能和工具将自己置于两个端点之间并截获数据;尽管交谈的两方认为他们是在与对方交谈,但是实际上他们是在与干坏事的人交流,这便是中间人攻击。中间人攻击是在运行在 HTTP 协议中的网络传输中常见的攻击手段,这种手段在 HTTP 协议中无法防御,因为 C/S 双方都无法确认对方的身份。

中间人攻击有几种攻击方式?

  1. 嗅探。嗅探或数据包嗅探是一种用于捕获流进和流出系统/网络的数据包的技术。网络中的数据包嗅探就好像电话中的监听。

  2. 数据包注入。在这种技术中,攻击者会将恶意数据包注入常规数据中。这样用户便不会注意到文件/恶意软件,因为它们是合法通讯流的一部分。

  3. 会话劫持。在你登录进你的银行账户和退出登录这一段期间便称为一个会话。这些会话通常都是黑客的攻击目标,因为它们包含潜在的重要信息。在大多数案例中,黑客会潜伏在会话中,并最终控制它。

  4. SSL剥离。在 SSL 剥离攻击中,攻击者使 SSL/TLS 协议剥落,随之协议便从安全的 HTTPS 协议变成了不安全的 HTTP 协议。

HTTPS 如何防范中间人攻击:

请见 HTTPS 加密原理。

9、有哪些响应码,分别都代表什么意思?

  • 1** 信息,服务器收到请求,需要请求者继续执行操作
  • 2** 成功,操作被成功接收并处理
  • 3** 重定向,需要进一步的操作以完成请求
  • 4** 客户端错误,请求包含语法错误或无法完成请求
  • 5** 服务器错误,服务器在处理请求的过程中发生了错误

二、TCP/UDP (⭐⭐⭐)

1、为什么tcp要经过三次握手,四次挥手?

一次典型的无数据传输的 TCP 连接(包括建立连接、关闭连接)过程如下图所示:

TCP 连接过程

重要标志位

  • **ACK(Acknowledge)**:TCP协议规定,只有 ACK=1 时表示有效,也规定连接建立后所有发送的报文的ACK必须为1
  • SYN(Synchronization):在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使 SYN=1 和 ACK=1。因此, SYN 置 1 就表示这是一个连接请求或连接接受报文。
  • **Seq(Sequence Number)**:序号,标识当前握/挥手已经进行到了哪一步。
  • FIN(finish):用来释放一个连接。当 FIN=1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接
  • `ISN(Initial Sequence Number):初始序号值。

三次握手

第一次: 建立连接。客户端发送连接请求报文段,将 SYN 置为1,Seq 为ISN(c);然后,客户端进入 SYN_SEND 状态,等待服务器的确认;

第二次: 服务器收到 SYN 报文段。服务器收到客户端的 SYN 报文段,需要对这个 SYN 报文段进行确认,设置 ACK 为ISN(c)+1;同时,自己自己还要发送 SYN 请求信息,设置 SYN为1,Seq 设置为ISN(s);服务器端将上述所有信息放到一个报文段(即 SYN + ACK 报文段)中,一并发送给客户端,此时服务器进入 SYN_RECV 状态;

第三次: 客户端收到服务器的 SYN + ACK 报文段,然后将 ACK 设置为ISN(s)+1,Seq 设置为ISN(c)+1,向服务器发送 ACK 报文段,这个报文段发送完毕以后,客户端和服务器端都进入 ESTABLISHED 状态,完成 TCP 三次握手。

四次挥手

第一次: 主机1(可以是客户端,也可以是服务器端),设置 Seq 为K,设置 ACK 为L,向主机2发送一个 FIN 报文段;此时,主机1进入 FIN_WAIT_1 状态;这表示主机1没有数据要发送给主机2了;

第二次: 主机2收到了主机1发送的 FIN 报文段,设置 Seq 为L,设置 ACK 为K+1,向主机1回一个 ACK 报文段;主机1进入 FIN_WAIT_2 状态;主机2告诉主机1,我『同意』你的关闭请求;

第三次: 主机2向主机1发送 FIN 报文段,设置 Seq 为L,设置 ACK 为K+1,请求关闭连接,同时主机2进入 LAST_ACK 状态;

第四次: 主机1收到主机2发送的 FIN 报文段,设置 Seq 为K,设置 ACK 为L+1,向主机2发送 ACK 报文段,然后主机1进入 TIME_WAIT 状态;主机2收到主机1的 ACK 报文段以后,就关闭连接;此时,主机1等待2 MSL 后依然没有收到回复,则证明 Server 端已正常关闭,那好,主机1也可以关闭连接了。

『三次握手』的目的是『为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误』。主要目的是防止 Server 端一直等待,浪费资源。换句话说,即是为了保证服务端能收接受到客户端的信息并能做出正确的应答而进行前两次(第一次和第二次)握手,为了保证客户端能够接收到服务端的信息并能做出正确的应答而进行后两次(第二次和第三次)握手。

『四次挥手』原因是因为TCP是全双工模式,接收到 FIN 时意味将没有数据再发来,但是还是可以继续发送数据。

2、TCP 可靠传输原理实现(滑动窗口)。

  • 确认和重传。 接收方收到报文后就会进行确认,发送方一段时间没有收到确认就会重传。
  • 数据校验。
  • 数据合理分片与排序。 TCP会对数据进行分片,接收方会缓存为按序到达的数据,重新排序后再提交给应用层。
  • 流程控制。 当接收方来不及接收发送的数据时,则会提示发送方降低发送的速度,防止包丢失。
  • 拥塞控制。 当网络发生拥塞时,减少数据的发送。

关于滑动窗口、流量控制、拥塞控制实现原理请点击这里

3、TCP 和 UDP 的区别?

  1. TCP 基于连接,UDP 基于无连接;

  2. TCP 对系统资源的要求较多,UDP 较少;

  3. UDP 程序结构较简单;

  4. TCP 是流模式,UDP 是数据报模式 ;

  5. TCP 保证数据可靠性,UDP 可能丢包;

  6. TCP 保证数据顺序,UDP 不保证。

4、如何设计在 UDP 上层保证 UDP 的可靠性传输?

传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照 TCP 可靠性传输的方式。如不考虑拥塞处理,可靠 UDP 的简单设计如下:

  1. 添加 Seq/ACK 机制,确保数据发送到对端;
  2. 添加发送和接收缓冲区,主要是用户超时重传;
  3. 添加超时重传机制。

具体过程即是:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。

目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT:

1、RUDP(Reliable User Datagram Protocol)

RUDP 提供一组数据服务质量增强机制,如拥塞控制的改进、重发机制及淡化服务器算法等。

2、RTP(Real Time Protocol)

RTP为数据提供了具有实时特征的端对端传送服务,如在组播或单播网络服务下的交互式视频音频或模拟数据。

3、UDT(UDP-based Data Transfer Protocol)

UDT的主要目的是支持高速广域网上的海量数据传输。

关于RUDP、RTP、UDT的更多介绍请查看此处

三、其它重要网络概念 (⭐⭐)

1、socket断线重连怎么实现,心跳机制又是怎样实现?

socket概念

套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应 用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

建立socket连接

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。

套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

  • 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
  • 客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端- - 套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
    连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

SOCKET连接与TCP连接

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

Socket连接与HTTP连接

由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网 络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。

而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。

很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数 据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求, 不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。TCP(Transmission Control Protocol) 传输控制协议

socket断线重连实现

正常连接断开客户端会给服务端发送一个fin包,服务端收到fin包后才会知道连接断开。
而断网断电时客户端无法发送fin包给服务端,所以服务端没办法检测到客户端已经短线。
为了缓解这个问题,服务端需要有个心跳逻辑,就是服务端检测到某个客户端多久没发送任何数据过来就认为客户端已经断开,
这需要客户端定时向服务端发送心跳数据维持连接。

心跳机制实现

长连接的实现:心跳机制,应用层协议大多都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线。并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议

1、在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。
系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。
而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。通过使用TCP的KeepAlive机制(修改那个time参数),可以让连接每隔一小段时间就产生一些ack包,以降低被踢掉的风险,当然,这样的代价是额外的网络和CPU负担。

2、应用层心跳机制实现。

2、Cookie与Session的作用和原理。

  • Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中。
  • Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

Session:

由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的。

具体到Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。因此从上述的定义中我们可以看到,Session实际上是一个特定的时间概念。

当客户端访问服务器时,服务器根据需求设置Session,将会话信息保存在服务器上,同时将标示Session的SessionId传递给客户端浏览器,

浏览器将这个SessionId保存在内存中,我们称之为无过期时间的Cookie。浏览器关闭后,这个Cookie就会被清掉,它不会存在于用户的Cookie临时文件。

以后浏览器每次请求都会额外加上这个参数值,服务器会根据这个SessionId,就能取得客户端的数据信息。

如果客户端浏览器意外关闭,服务器保存的Session数据不是立即释放,此时数据还会存在,只要我们知道那个SessionId,就可以继续通过请求获得此Session的信息,因为此时后台的Session还存在,当然我们可以设置一个Session超时时间,一旦超过规定时间没有客户端请求时,服务器就会清除对应SessionId的Session信息。

Cookie是由服务器端生成,发送给User-Agent(一般是web浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用Cookie)。Cookie名称和值可以由服务器端开发自己定义,对于JSP而言也可以直接写入Sessionid,这样服务器可以知道该用户是否合法用户以及是否需要重新登录等。

3、IP报文中的内容。

IP 报文结构图

版本:IP协议的版本,目前的IP协议版本号为4,下一代IP协议版本号为6。

首部长度:IP报头的长度。固定部分的长度(20字节)和可变部分的长度之和。共占4位。最大为1111,即10进制的15,代表IP报头的最大长度可以为15个32bits(4字节),也就是最长可为15*4=60字节,除去固定部分的长度20字节,可变部分的长度最大为40字节。

服务类型:Type Of Service。

总长度:IP报文的总长度。报头的长度和数据部分的长度之和。

标识:唯一的标识主机发送的每一分数据报。通常每发送一个报文,它的值加一。当IP报文长度超过传输网络的MTU(最大传输单元)时必须分片,这个标识字段的值被复制到所有数据分片的标识字段中,使得这些分片在达到最终目的地时可以依照标识字段的内容重新组成原先的数据。

标志:共3位。R、DF、MF三位。目前只有后两位有效,DF位:为1表示不分片,为0表示分片。MF:为1表示“更多的片”,为0表示这是最后一片。

片位移:本分片在原先数据报文中相对首位的偏移位。(需要再乘以8)

生存时间:IP报文所允许通过的路由器的最大数量。每经过一个路由器,TTL减1,当为0时,路由器将该数据报丢弃。TTL 字段是由发送端初始设置一个 8 bit字段.推荐的初始值由分配数字 RFC 指定,当前值为 64。发送 ICMP 回显应答时经常把 TTL 设为最大值 255。

协议:指出IP报文携带的数据使用的是那种协议,以便目的主机的IP层能知道要将数据报上交到哪个进程(不同的协议有专门不同的进程处理)。和端口号类似,此处采用协议号,TCP的协议号为6,UDP的协议号为17。ICMP的协议号为1,IGMP的协议号为2.

首部校验和:计算IP头部的校验和,检查IP报头的完整性。

源IP地址:标识IP数据报的源端设备。

目的IP地址:标识IP数据报的目的地址。

最后就是可变部分和数据部分。

四、常见网络流程机制 (⭐⭐)

1、浏览器输入地址到返回结果发生了什么?

总体来说分为以下几个过程:

1、DNS解析,此外还有DNSy优化(DNS缓存、DNS负载均衡)

2、TCP连接

3、发送HTTP请求

4、服务器处理请求并返回HTTP报文

5、浏览器解析渲染页面

6、连接结束

Web前端的本质

将信息快速并友好的展示给用户并能够与用户进行交互。

如何尽快的加载资源(网络优化)?

答案就是能不从网络中加载的资源就不从网络中加载,当我们合理使用缓存,将资源放在浏览器端,这是最快的方式。如果资源必须从网络中加载,则要考虑缩短连接时间,即DNS优化部分;减少响应内容大小,即对内容进行压缩。另一方面,如果加载的资源数比较少的话,也可以快速的响应用户。