---
title: 网络协议等总结
categories:
- 计算机网络
---

* 目录
{:toc}

### 1.TCP报头格式

* 端口号：用来标识同一台计算机的不同的应用进程。计算机网络通过端口号实现复用/分用
        
        
        1.源端口：源端口和IP地址的作用是标识报文的返回地址。
        2.目的端口：端口指明接收方计算机上的应用程序接口。
        TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。
    
* 序号和确认号：是TCP可靠传输的关键部分。序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中，每一个字节一个序号。
e.g.一个报文段的序号为300，此报文段数据部分共有100字节，则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。
确认号，即ACK，指明下一个期待收到的字节序号，表明该序号之前的所有数据已经正确无误的收到。
确认号只有当ACK标志为1时才有效。比如建立连接时，SYN报文的ACK标志位为0。

* 数据偏移 | 首部长度：4bits。由于首部可能含有可选项内容，因此TCP报头的长度是不确定的，报头不包含任何任选字段则长度为20字节，
4位首部长度字段所能表示的最大值为1111，转化为10进制为15，15*32/8 = 60，故报头最大长度为60字节。
首部长度也叫数据偏移，是因为首部长度实际上指示了数据区在报文段中的起始偏移值。

* 保留：为将来定义新的用途保留，现在一般置0。

* 控制位：URG  ACK  PSH  RST  SYN  FIN，共6个，每一个标志位表示一个控制功能。

    
        1.URG：紧急指针标志，为1时表示紧急指针有效，为0则忽略紧急指针。
        2.ACK：确认序号标志，为1时表示确认号有效，为0表示报文中不含确认信息，忽略确认号字段。
        3.PSH：push标志，为1表示是带有push标志的数据，指示接收方在接收到该报文段以后，应尽快将这个报文段交给应用程序，而不是在缓冲区排队。
        4.RST：重置连接标志，用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。
        5.SYN：同步序号，用于建立连接过程，在连接请求中，SYN=1和ACK=0表示该数据段没有使用捎带的确认域，而连接应答捎带一个确认，即SYN=1和ACK=1。
        6.FIN：finish标志，用于释放连接，为1时表示发送方已经没有数据发送了，即关闭本方数据流。

* 窗口：滑动窗口大小，用来告知发送端接受端的缓存大小，以此控制发送端发送数据的速率，从而达到流量控制。窗口大小时一个16bit字段，因而窗口大小最大为65535。

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

* 紧急指针：只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量，和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 
TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。

* 选项和填充：最常见的可选字段是最长报文大小，又称为MSS「Maximum Segment Size」，每个连接方通常都在通信的第一个报文段「为建立连接而设置SYN标志为1的那个段」中指明这个选项，
它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍，所以要加填充位，即在这个字段中加入额外的零，以保证TCP头是32的整数倍。

* 数据部分： TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时，双方交换的报文段仅有 TCP 首部。
如果一方没有数据要发送，也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中，也会发送不带任何数据的报文段

### 2.UDP报头格式

1. 源端口号：发送端端口号「16位」
2. 目的端口号：接收端端口号「16位」
3. 用户数据报长度：包括报头和用户数据在内的总字节数。「16位」
4. 校验和：对报头和用户数据进行校验。「16位」

在linux中结构体如下所示：
```
/usr/include/udp.h
struct udphdr {
__be16      source;      //源端口号
__be16      dest;        //目的端口号
__be16       len;        //用户数据报长度
__sum16      check;      //校验和
};
```

补充1：因为传输层主要解决的问题是端到端通信，网络层主要解决的是点到点通信，所以传输层只需要端口号，而具体点到点的连接由下层网络层提供

一方面因为发送数据的时候，报文在传输层「分组后」，报文段将在网络层被打上IP的协议头「形成数据包」，此时端口+IP已经组成，唯一确定一台机器的一个进程。
相反，在接收数据的时候，首先通过IP唯一定位一台机器「局域网临时IP唯一，广域网公网IP唯一」，并在数据包传至传输层的时候对数据包进行拆包，形成报文段，此时报文段只需要端口即可，
因为具体的机器在网络层已经确定，而此时使用端口确定具体的进程「应用」即可

补充2：什么是校检和？用什么校检？

循环冗余校验「Cyclic Redundancy Check, CRC」是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的一种散列函数，主要用来检测或校验数据传输或者保存后可能出现的错误。
它是利用除法及余数的原理来作错误侦测的。

在CRC算法中，将二进制数据流作为多项式的系数，然后进行的是多项式的乘除法。

比如说我们有两个二进制数，分别为：1101 和1011。</br>
1101 与如下的多项式相联系：1x3+1x2+0x1+1x0=x3+x2+x0「意为x的n次方」。</br>
1011与如下的多项式相联系：1x3+0x2+1x1+1x0=x3+x1+x0。</br>
两个多项式的乘法：「x3+x2+x0」「x3+x1+x0」=x6+x5+x4+x3+x3+x3+x2+x1+x0。</br>
得到结果后，合并同类项时采用模2运算。「乘除法采用正常的多项式乘除法，而加减法都采用模2运算，所谓模2运算就是结果除以2后取余数。」</br>
比如3 mod 2 = 1。因此，上面最终得到的多项式为：x6+x5+x4+x3+x2+x1+x0，对应的二进制数:111111，加减法采用模2运算后其实就成了一种异或运算了。

CRC 算法的基本思想是将传输的数据当做一个位数很长的数。将这个数除以另一个数，得到的余数作为校验数据附加到原数据后面。

为了进行CRC运算，也就是这种特殊的除法运算，必须要指定个被除数，在CRC算法中，这个被除数有一个专有名称叫做“生成多项式”。
生成多项式的选取是个很有难度的问题，如果选的不好，那么检出错误的概率就会低很多。
好在这个问题已经被专家们研究了很长一段时间了，对于我们这些使用者来说，只要把现成的成果拿来用就行了。

首先TCP，UDP，IP三个协议中校验和都占16位，也就是两个字节。

UDP的校验和结算相对简单。首先UDP报文长度不是确定的，所以计算校验和前要先将报文的末尾用‘0’补齐。使报文为偶数个字节。
一旦验证UDP报文出错时，报文在分组转发时，正常发送转发，不会被丢弃。他被丢弃的地方发生在应用层向上转发的时候。一般路由器等三层设备，不会验证其校验和！
UDP的校验是可选的，也就是可以选择接收端是否对其进行校验！

    发送端计算校验和: 
    
    计算UDP的校验和方法是计算16位的二进制和包括UDP首部、数据，将校验和字段「16位」置0，
    将每个16位的按位相加，第17、18位出现进位的话，将结果值重新与结果的第1，2位相加，再将所得的结果取反码，
    最后得到的结果即为UDP校验和，存在校验和字段中。
    
    接收端验证校验和：
    
    若传输中没有任何差错，包含之前的校验和对报文进行二进制反码求和，接收端计算的结果为全1，即报文正确，否则有错。

TCP的校验和算法和UDP的基本相同，不够偶数个字节同样需要‘0’填充。求法也是将每个16位进行二进制反码求和。但是不同的地方，
TCP必须进行校验，而且他有自己的一些重传机制，来确保可靠传输。检验和的算法几个协议都是相同的，唯一不同就是IP协议只验证头部。求校验和时，他并不包括数据部分。

PS:CRC它是不会进行纠错的，通常是让信息的发送方重发一遍。

### 3.TCP/UDP区别

TCP和UDP是OSI模型中的运输层中的协议。TCP提供可靠的通信传输，而UDP则常被用于让广播和细节控制交给应用的通信传输。

TCP与UDP基本区别：

* 基于连接与无连接。
* TCP要求系统资源较多，UDP较少。
* UDP程序结构较简单。
* 流模式「TCP」与数据报模式「UDP」。
* TCP保证数据正确性，UDP可能丢包。
* TCP保证数据顺序，UDP不保证。「这里的有序不是绝对有序，而是逻辑上通过seq实现」
* TCP面向连接「如打电话要先拨号建立连接」;UDP是无连接的，即发送数据之前不需要建立连接。
* TCP提供可靠的服务。也就是说，通过TCP连接传送的数据，无差错，不丢失，不重复，且按序到达;UDP尽最大努力交付，即不保证可靠交付。
* TCP面向字节流，实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的，UDP没有拥塞控制，因此网络出现拥塞不会使源主机的发送速率降低「对实时应用很有用，如IP电话，实时视频会议等」。
* 每一条TCP连接只能是点到点的;UDP支持一对一，一对多，多对一和多对多的交互通信。
* TCP首部开销20字节;UDP的首部开销小，只有8个字节。
* TCP的逻辑通信信道是全双工的可靠信道，UDP则是不可靠信道。


         1.TCP「Transmission Control Protocol 传输控制协议」是一种面向连接的、可靠的、基于字节流的传输层通信协议，由IETF的RFC 793定义。
        在简化的计算机网络OSI模型中，完成第四层传输层所指定的功能。
         2.UDP 是User Datagram Protocol的简称， 中文名是用户数据报协议，是OSI「Open System Interconnection，开放式系统互联」 
         参考模型中一种无连接的传输层协议，提供面向报文的简单不可靠信息传送服务IETF RFC 768是UDP的正式规范。UDP在IP报文的协议号是17。
    
### 4.HTTP状态码

* HTTP: Status 200 – 服务器成功返回网页
* HTTP: Status 3xx - 表示要完成请求，需要进一步操作。 通常，这些状态代码用来重定向
* HTTP: Status 404 – 请求的网页不存在
* HTTP: Status 503 – 服务不可用

定义：所有状态码的第一个数字代表了响应的五种状态之一。

1、消息「1字头」

这一类型的状态码，代表请求已被接受，需要继续处理。这类响应是临时响应，只包含状态行和某些可选的响应头信息，并以空行结束。由于 HTTP/1.0 协议中没有定义任何 1xx 状态码，所以除非在某些试验条件下，服务器禁止向此类客户端发送 1xx 响应。

* 100 Continue
客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收，且仍未被拒绝。客户端应当继续发送请求的剩余部分，或者如果请求已经完成，忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。
* 101 Switching Protocols
服务器已经理解了客户端的请求，并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后，服务器将会切换到在Upgrade 消息头中定义的那些协议。
只有在切换新的协议更有好处的时候才应该采取类似措施。例如，切换到新的HTTP 版本比旧版本更有优势，或者切换到一个实时且同步的协议以传送利用此类特性的资源。
* 102 Processing
由WebDAV「RFC 2518」扩展的状态码，代表处理将被继续执行。

2、成功「2字头」

这一类型的状态码，代表请求已成功被服务器接收、理解、并接受

* 200 OK
请求已成功，请求所希望的响应头或数据体将随此响应返回。
* 201 Created
请求已经被实现，而且有一个新的资源已经依据请求的需要而建立，且其 URI 已经随Location 头信息返回。假如需要的资源无法及时建立的话，应当返回 '202 Accepted'。
* 202 Accepted
服务器已接受请求，但尚未处理。正如它可能被拒绝一样，最终该请求可能会也可能不会被执行。在异步操作的场合下，没有比发送这个状态码更方便的做法了。
返回202状态码的响应的目的是允许服务器接受其他过程的请求「例如某个每天只执行一次的基于批处理的操作」，而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。
在接受请求处理并返回202状态码的响应应当在返回的实体中包含一些指示处理当前状态的信息，以及指向处理状态监视器或状态预测的指针，以便用户能够估计操作是否已经完成。
* 203 Non-Authoritative Information
服务器已成功处理了请求，但返回的实体头部元信息不是在原始服务器上有效的确定集合，而是来自本地或者第三方的拷贝。当前的信息可能是原始版本的子集或者超集。例如，包含资源的元数据可能导致原始服务器知道元信息的超集。
使用此状态码不是必须的，而且只有在响应不使用此状态码便会返回200 OK的情况下才是合适的。
* 204 No Content
服务器成功处理了请求，但不需要返回任何实体内容，并且希望返回更新了的元信息。响应可能通过实体头部的形式，返回新的或更新后的元信息。如果存在这些头部信息，则应当与所请求的变量相呼应。
如果客户端是浏览器的话，那么用户浏览器应保留发送了该请求的页面，而不产生任何文档视图上的变化，即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。
由于204响应被禁止包含任何消息体，因此它始终以消息头后的第一个空行结尾。
* 205 Reset Content
服务器成功处理了请求，且没有返回任何内容。但是与204响应不同，返回此状态码的响应要求请求者重置文档视图。该响应主要是被用于接受用户输入后，立即重置表单，以便用户能够轻松地开始另一次输入。
与204响应一样，该响应也被禁止包含任何消息体，且以消息头后的第一个空行结束。
* 206 Partial Content
服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
该请求必须包含 Range 头信息来指示客户端希望得到的内容范围，并且可能包含 If-Range 来作为请求条件。
响应必须包含如下的头部域：
Content-Range 用以指示本次响应中返回的内容的范围；如果是 Content-Type 为 multipart/byteranges 的多段下载，则每一 multipart 段中都应包含 Content-Range 域用以指示本段的内容范围。
假如响应中包含 Content-Length，那么它的数值必须匹配它返回的内容范围的真实字节数。
Date
ETag 和/或 Content-Location，假如同样的请求本应该返回200响应。
Expires， Cache-Control，和/或 Vary，假如其值可能与之前相同变量的其他响应对应的值不同的话。
假如本响应请求使用了 If-Range 强缓存验证，那么本次响应不应该包含其他实体头；假如本响应的请求使用了 If-Range 弱缓存验证，那么本次响应禁止包含其他实体头；这避免了缓存的实体内容和更新了的实体头信息之间的不一致。
否则，本响应就应当包含所有本应该返回200响应中应当返回的所有实体头部域。
假如 ETag 或 Last-Modified 头部不能精确匹配的话，则客户端缓存应禁止将206响应返回的内容与之前任何缓存过的内容组合在一起。
* 207 Multi-Status
由WebDAV「RFC 2518」扩展的状态码，代表之后的消息体将是一个XML消息，并且可能依照之前子请求数量的不同，包含一系列独立的响应代码。

3、重定向「3字头」

这类状态码代表需要客户端采取进一步的操作才能完成请求。通常，这些状态码用来重定向，后续的请求地址「重定向目标」在本次响应的 Location 域中指明。
当且仅当后续的请求所使用的方法是 GET 或者 HEAD 时，用户浏览器才可以在没有用户介入的情况下自动提交所需要的后续请求。客户端应当自动监测无限循环重定向「例如：A->A，或者A->B->C->A」，因为这会导致服务器和客户端大量不必要的资源消耗。
按照 HTTP/1.0 版规范的建议，浏览器不应自动访问超过5次的重定向。

* 300 Multiple Choices
被请求的资源有一系列可供选择的回馈信息，每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
除非这是一个 HEAD 请求，否则该响应应当包括一个资源特性及地址的列表的实体，以便用户或浏览器从中选择最合适的重定向地址。这个实体的格式由 Content-Type 定义的格式所决定。浏览器可能根据响应的格式以及浏览器自身能力，自动作出最合适的选择。
当然，RFC 2616规范并没有规定这样的自动选择该如何进行。
如果服务器本身已经有了首选的回馈选择，那么在 Location 中应当指明这个回馈的 URI；浏览器可能会将这个 Location 值作为自动重定向的地址。此外，除非额外指定，否则这个响应也是可缓存的。
* 301 Moved Permanently
被请求的资源已永久移动到新位置，并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能，拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定，否则这个响应也是可缓存的。
新的永久性的URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求，否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。
如果这不是一个 GET 或者 HEAD 请求，因此浏览器禁止自动进行重定向，除非得到用户的确认，因为请求的条件可能因此发生变化。
注意：对于某些使用 HTTP/1.0 协议的浏览器，当它们发送的 POST 请求得到了一个301响应的话，接下来的重定向请求将会变成 GET 方式。
* 302 Move temporarily
请求的资源临时从不同的 URI响应请求。由于这样的重定向是临时的，客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下，这个响应才是可缓存的。
上文有提及。
如果这不是一个 GET 或者 HEAD 请求，那么浏览器禁止自动进行重定向，除非得到用户的确认，因为请求的条件可能因此发生变化。
注意：虽然RFC 1945和RFC 2068规范不允许客户端在重定向时改变请求的方法，但是很多现存的浏览器将302响应视作为303响应，并且使用 GET 方式访问在 Location 中规定的 URI，而无视原先请求的方法。
状态码303和307被添加了进来，用以明确服务器期待客户端进行何种反应。
* 303 See Other
对应当前请求的响应可以在另一个 URI 上被找到，而且客户端应当采用 GET 的方式访问那个资源。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。这个新的 URI 不是原始资源的替代引用。
同时，303响应禁止被缓存。当然，第二个请求「重定向」可能被缓存。
注意：许多 HTTP/1.1 版以前的浏览器不能正确理解303状态。如果需要考虑与这些浏览器之间的互动，302状态码应该可以胜任，因为大多数的浏览器处理302响应时的方式恰恰就是上述规范要求客户端处理303响应时应当做的。
* 304 Not Modified
如果客户端发送了一个带条件的 GET 请求且该请求已被允许，而文档的内容「自上次访问以来或者根据请求的条件」并没有改变，则服务器应当返回这个状态码。304响应禁止包含消息体，因此始终以消息头后的第一个空行结尾。
该响应必须包含以下的头信息：
Date，除非这个服务器没有时钟。假如没有时钟的服务器也遵守这些规则，那么代理服务器以及客户端可以自行将 Date 字段添加到接收到的响应头中去「正如RFC 2068中规定的一样」，缓存机制将会正常工作。
ETag 和/或 Content-Location，假如同样的请求本应返回200响应。
Expires， Cache-Control，和/或Vary，假如其值可能与之前相同变量的其他响应对应的值不同的话。
假如本响应请求使用了强缓存验证，那么本次响应不应该包含其他实体头；否则「例如，某个带条件的 GET 请求使用了弱缓存验证」，本次响应禁止包含其他实体头；这避免了缓存了的实体内容和更新了的实体头信息之间的不一致。
假如某个304响应指明了当前某个实体没有缓存，那么缓存系统必须忽视这个响应，并且重复发送不包含限制条件的请求。
假如接收到一个要求更新某个缓存条目的304响应，那么缓存系统必须更新整个条目以反映所有在响应中被更新的字段的值。
* 305 Use Proxy
被请求的资源必须通过指定的代理才能被访问。Location 域中将给出指定的代理所在的 URI 信息，接收者需要重复发送一个单独的请求，通过这个代理才能访问相应资源。只有原始服务器才能建立305响应。
注意：RFC 2068中没有明确305响应是为了重定向一个单独的请求，而且只能被原始服务器建立。忽视这些限制可能导致严重的安全后果。
* 306 Switch Proxy
在最新版的规范中，306状态码已经不再被使用。
* 307 Temporary Redirect
请求的资源临时从不同的URI 响应请求。
新的临时性的URI 应当在响应的 Location 域中返回。除非这是一个HEAD 请求，否则响应的实体中应当包含指向新的URI 的超链接及简短说明。因为部分浏览器不能识别307响应，因此需要添加上述必要信息以便用户能够理解并向新的 URI 发出访问请求。
如果这不是一个GET 或者 HEAD 请求，那么浏览器禁止自动进行重定向，除非得到用户的确认，因为请求的条件可能因此发生变化。

4、请求错误「4字头」

这类的状态码代表了客户端看起来可能发生了错误，妨碍了服务器的处理。除非响应的是一个 HEAD 请求，否则服务器就应该返回一个解释当前错误状况的实体，以及这是临时的还是永久性的状况。
这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。
如果错误发生时客户端正在传送数据，那么使用TCP的服务器实现应当仔细确保在关闭客户端与服务器之间的连接之前，客户端已经收到了包含错误信息的数据包。
如果客户端在收到错误信息后继续向服务器发送数据，服务器的TCP栈将向客户端发送一个重置数据包，以清除该客户端所有还未识别的输入缓冲，以免这些数据被服务器上的应用程序读取并干扰后者。

* 400 Bad Request
1.语义有误，当前请求无法被服务器理解。除非进行修改，否则客户端不应该重复提交这个请求。
2.请求参数有误。
* 401 Unauthorized
当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization 证书，那么401响应代表着服务器验证已经拒绝了那些证书。
如果401响应包含了与前一个响应相同的身份验证询问，且浏览器已经至少尝试了一次验证，那么浏览器应当向用户展示响应中包含的实体信息，因为这个实体信息中可能包含了相关诊断信息。参见RFC 2617。
* 402 Payment Required
该状态码是为了将来可能的需求而预留的。
* 403 Forbidden
服务器已经理解请求，但是拒绝执行它。与401响应不同的是，身份验证并不能提供任何帮助，而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求，而且服务器希望能够讲清楚为何请求不能被执行，那么就应该在实体内描述拒绝的原因。
当然服务器也可以返回一个404响应，假如它不希望让客户端获得任何信息。
* 404 Not Found
请求失败，请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话，应当使用410状态码来告知旧资源因为某些内部的配置机制问题，已经永久的不可用，而且没有任何可以跳转的地址。
404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
出现这个错误的最有可能的原因是服务器端没有这个页面。
* 405 Method Not Allowed
请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。
鉴于 PUT，DELETE 方法会对服务器上的资源进行写操作，因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法，对于此类请求均会返回405错误。
* 406 Not Acceptable
请求的资源的内容特性无法满足请求头中的条件，因而无法生成响应实体。
除非这是一个 HEAD 请求，否则该响应就应当返回一个包含可以让用户或者浏览器从中选择最合适的实体特性以及地址列表的实体。实体的格式由 Content-Type 头中定义的媒体类型决定。
浏览器可以根据格式及自身能力自行作出最佳选择。但是，规范中并没有定义任何作出此类自动选择的标准。
* 407 Proxy Authentication Required
与401响应类似，只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。参见RFC 2617。
* 408 Request Timeout
请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。
* 409 Conflict
由于和被请求的资源的当前状态之间存在冲突，请求无法完成。这个代码只允许用在这样的情况下才能被使用：用户被认为能够解决冲突，并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。
冲突通常发生于对 PUT 请求的处理中。例如，在采用版本检查的环境下，某次 PUT 提交的对特定资源的修改请求所附带的版本信息与之前的某个「第三方」请求向冲突，那么此时服务器就应该返回一个409错误，告知用户请求无法完成。
此时，响应实体中很可能会包含两个冲突版本之间的差异比较，以便用户重新提交归并以后的新版本。
* 410 Gone
被请求的资源在服务器上已经不再可用，而且没有任何已知的转发地址。这样的状况应当被认为是永久性的。如果可能，拥有链接编辑功能的客户端应当在获得用户许可后删除所有指向这个地址的引用。
如果服务器不知道或者无法确定这个状况是否是永久的，那么就应该使用404状态码。除非额外说明，否则这个响应是可缓存的。
410响应的目的主要是帮助网站管理员维护网站，通知用户该资源已经不再可用，并且服务器拥有者希望所有指向这个资源的远端连接也被删除。这类事件在限时、增值服务中很普遍。同样，410响应也被用于通知客户端在当前服务器站点上，原本属于某个个人的资源已经不再可用。
当然，是否需要把所有永久不可用的资源标记为'410 Gone'，以及是否需要保持此标记多长时间，完全取决于服务器拥有者。
* 411 Length Required
服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后，客户端可以再次提交该请求。
* 412 Precondition Failed
服务器在验证在请求的头字段中给出先决条件时，没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息「请求头字段数据」中设置先决条件，以此避免该请求方法被应用到其希望的内容以外的资源上。
* 413 Request Entity Too Large
服务器拒绝处理当前请求，因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下，服务器可以关闭连接以免客户端继续发送此请求。
如果这个状况是临时的，服务器应当返回一个 Retry-After 的响应头，以告知客户端可以在多少时间以后重新尝试。
* 414 Request-URI Too Long
请求的URI 长度超过了服务器能够解释的长度，因此服务器拒绝对该请求提供服务。这比较少见，通常的情况包括：
本应使用POST方法的表单提交变成了GET方法，导致查询字符串「Query String」过长。
重定向URI “黑洞”，例如每次重定向把旧的 URI 作为新的 URI 的一部分，导致在若干次重定向后 URI 超长。
客户端正在尝试利用某些服务器中存在的安全漏洞攻击服务器。这类服务器使用固定长度的缓冲读取或操作请求的 URI，当 GET 后的参数超过某个数值后，可能会产生缓冲区溢出，导致任意代码被执行[1]。没有此类漏洞的服务器，应当返回414状态码。
* 415 Unsupported Media Type
对于当前请求的方法和所请求的资源，请求中提交的实体并不是服务器中所支持的格式，因此请求被拒绝。
* 416 Requested Range Not Satisfiable
如果请求中包含了 Range 请求头，并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合，同时请求中又没有定义 If-Range 请求头，那么服务器就应当返回416状态码。
假如 Range 使用的是字节范围，那么这种情况就是指请求指定的所有数据范围的首字节位置都超过了当前资源的长度。服务器也应当在返回416状态码的同时，包含一个 Content-Range 实体头，用以指明当前资源的长度。
这个响应也被禁止使用 multipart/byteranges 作为其 Content-Type。
* 417 Expectation Failed
在请求头 Expect 中指定的预期内容无法被服务器满足，或者这个服务器是一个代理服务器，它有明显的证据证明在当前路由的下一个节点上，Expect 的内容无法被满足。
* 421 There are too many connections from your internet address
从当前客户端所在的IP地址到服务器的连接数超过了服务器许可的最大范围。通常，这里的IP地址指的是从服务器上看到的客户端地址「比如用户的网关或者代理服务器地址」。在这种情况下，连接数的计算可能涉及到不止一个终端用户。
* 422 Unprocessable Entity
请求格式正确，但是由于含有语义错误，无法响应。「RFC 4918 WebDAV」
* 423 Locked
当前资源被锁定。「RFC 4918 WebDAV」
* 424 Failed Dependency
由于之前的某个请求发生的错误，导致当前请求失败，例如 PROPPATCH。「RFC 4918 WebDAV」
* 425 Unordered Collection
在WebDav Advanced Collections 草案中定义，但是未出现在《WebDAV 顺序集协议》「RFC 3658」中。
* 426 Upgrade Required
客户端应当切换到TLS/1.0。「RFC 2817」
* 449 Retry With
由微软扩展，代表请求应当在执行完适当的操作后进行重试。

5、服务器错误「5字头」

这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生，也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。
除非这是一个HEAD 请求，否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。
这些状态码适用于任何响应方法。

* 500 Internal Server Error
服务器遇到了一个未曾预料的状况，导致了它无法完成对请求的处理。一般来说，这个问题都会在服务器端的源代码出现错误时出现。
* 501 Not Implemented
服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法，并且无法支持其对任何资源的请求。
* 502 Bad Gateway
作为网关或者代理工作的服务器尝试执行请求时，从上游服务器接收到无效的响应。
* 503 Service Unavailable
由于临时的服务器维护或者过载，服务器当前无法处理请求。这个状况是临时的，并且将在一段时间以后恢复。如果能够预计延迟时间，那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。
如果没有给出这个 Retry-After 信息，那么客户端应当以处理500响应的方式处理它。
注意：503状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是希望拒绝客户端的连接。
* 504 Gateway Timeout
作为网关或者代理工作的服务器尝试执行请求时，未能及时从上游服务器「URI标识出的服务器，例如HTTP、FTP、LDAP」或者辅助服务器「例如DNS」收到响应。
注意：某些代理服务器在DNS查询超时时会返回400或者500错误
* 505 HTTP Version Not Supported
服务器不支持，或者拒绝支持在请求中使用的 HTTP 版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。
* 506 Variant Also Negotiates
由《透明内容协商协议》「RFC 2295」扩展，代表服务器存在内部配置错误：被请求的协商变元资源被配置为在透明内容协商中使用自己，因此在一个协商处理中不是一个合适的重点。
* 507 Insufficient Storage
服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。WebDAV 「RFC 4918」
* 509 Bandwidth Limit Exceeded
服务器达到带宽限制。这不是一个官方的状态码，但是仍被广泛使用。
* 510 Not Extended
获取资源所需要的策略并没有没满足。「RFC 2774」
* 600 Unparseable Response Headers
源站没有返回响应头部，只返回实体内容

### 5.HTTP协议 一些报头字段的作用

1. 我们知道HTTP协议采用“请求-应答”模式，当使用普通模式，即非KeepAlive模式时，每个请求/应答客户和服务器都要新建一个连接，完成 之后立即断开连接「HTTP协议为无连接的协议」
当使用Keep-Alive模式「又称持久连接、连接重用」时，Keep-Alive功能使客户端到服 务器端的连接持续有效，当出现对服务器的后继请求时，Keep-Alive功能避免了建立或者重新建立连接。
2. http 1.0中默认是关闭的，需要在http头加入"Connection: Keep-Alive"，才能启用Keep-Alive；http 1.1中默认启用Keep-Alive，如果加入"Connection: close "，才关闭。
目前大部分浏览器都是用http1.1协议，也就是说默认都会发起Keep-Alive的连接请求了，所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。
3. 启用Keep-Alive的优点
从上面的分析来看，启用Keep-Alive模式肯定更高效，性能更高。因为避免了建立/释放连接的开销。
4. 下面是RFC 2616 上的总结：

* 1.Accept：告诉WEB服务器自己接受什么介质类型，```*/* ```表示任何类型，```type/*``` 表示该类型下的所有子类型，type/sub-type。
* 2.Accept-Charset： 浏览器申明自己接收的字符集 
Accept-Encoding： 浏览器申明自己接收的编码方法，通常指定压缩方法，是否支持压缩，支持什么压缩方法「gzip，deflate」 
Accept-Language：浏览器申明自己接收的语言 
语言跟字符集的区别：中文是语言，中文有多种字符集，比如big5，gb2312，gbk等等。
* 3.Accept-Ranges：WEB服务器表明自己是否接受获取其某个实体的一部分「比如文件的一部分」的请求。bytes：表示接受，none：表示不接受。
* 4.Age：当代理服务器用自己缓存的实体去响应请求时，用该头部表明该实体从产生到现在经过多长时间了。
* 5.Authorization：当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时，用该头部来回应自己的身份验证信息给WEB服务器。
* 6.Cache-Control：请求：no-cache「不要缓存的实体，要求现在从WEB服务器去取」 
max-age：「只接受 Age 值小于 max-age 值，并且没有过期的对象」 
max-stale：「可以接受过去的对象，但是过期时间必须小于 max-stale 值」 
min-fresh：「接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象」 
响应：public「可以用 Cached 内容回应任何用户」 
private「只能用缓存内容回应先前请求该内容的那个用户」 
no-cache「可以缓存，但是只有在跟WEB服务器验证了其有效后，才能返回给客户端」 
max-age：「本响应包含的对象的过期时间」 
ALL: no-store「不允许缓存」
* 7.Connection：请求：close「告诉WEB服务器或者代理服务器，在完成本次请求的响应后，断开连接，不要等待本次连接的后续请求了」。 
keepalive「告诉WEB服务器或者代理服务器，在完成本次请求的响应后，保持连接，等待本次连接的后续请求」。 
响应：close「连接已经关闭」。 
keepalive「连接保持着，在等待本次连接的后续请求」。 
Keep-Alive：如果浏览器请求保持连接，则该头部表明希望 WEB 服务器保持连接多长时间「秒」。例如：Keep-Alive：300
* 8.Content-Encoding：WEB服务器表明自己使用了什么压缩方法「gzip，deflate」压缩响应中的对象。例如：Content-Encoding：gzip
* 9.Content-Language：WEB 服务器告诉浏览器自己响应的对象的语言。
* 10.Content-Length： WEB 服务器告诉浏览器自己响应的对象的长度。例如：Content-Length: 26012
* 11.Content-Range： WEB 服务器表明该响应包含的部分对象为整个对象的哪个部分。例如：Content-Range: bytes 21010-47021/47022
* 12.Content-Type： WEB 服务器告诉浏览器自己响应的对象的类型。例如：Content-Type：application/xml
* 13.ETag：就是一个对象「比如URL」的标志值，就一个对象而言，比如一个 html 文件，如果被修改了，其 Etag 也会别修改，所以ETag 的作用跟 Last-Modified 的作用差不多，主要供 WEB 服务器判断一个对象是否改变了。
比如前一次请求某个 html 文件时，获得了其 ETag，当这次又请求这个文件时，浏览器就会把先前获得的 ETag 值发送给WEB 服务器，然后 WEB 服务器会把这个 ETag 跟该文件的当前 ETag 进行对比，然后就知道这个文件有没有改变了。
* 14.Expired：WEB服务器表明该实体将在什么时候过期，对于过期了的对象，只有在跟WEB服务器验证了其有效性后，才能用来响应客户请求。是 HTTP/1.0 的头部。例如：Expires：Sat， 23 May 2009 10:02:12 GMT
* 15.Host：客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。例如：Host：rss.sina.com.cn
* 16.If-Match：如果对象的 ETag 没有改变，其实也就意味著对象没有改变，才执行请求的动作。
* 17.If-None-Match：如果对象的 ETag 改变了，其实也就意味著对象也改变了，才执行请求的动作。
* 18.If-Modified-Since：如果请求的对象在该头部指定的时间之后修改了，才执行请求的动作「比如返回对象」，否则返回代码304，告诉浏览器 该对象没有修改。例如：If-Modified-Since：Thu， 10 Apr 2008 09:14:42 GMT
* 19.If-Unmodified-Since：如果请求的对象在该头部指定的时间之后没修改过，才执行请求的动作「比如返回对象」。
* 20.If-Range：浏览器告诉 WEB 服务器，如果我请求的对象没有改变，就把我缺少的部分给我，如果对象改变了，就把整个对象给我。浏览器通过发送请求对象的 ETag 或者 自己所知道的最后修改时间给 WEB 服务器，让其判断对象是否改变了。总是跟 Range 头部一起使用。
* 21.Last-Modified：WEB 服务器认为对象的最后修改时间，比如文件的最后修改时间，动态页面的最后产生时间等等。例如：Last-Modified：Tue， 06 May 2008 02:42:43 GMT
* 22.Location：WEB 服务器告诉浏览器，试图访问的对象已经被移到别的位置了，到该头部指定的位置去取。例如：Location：```http://i0.sinaimg.cn/dy/deco/2008/0528/sinahome_0803_ws_005_text_0.gif```
* 23.Pramga：主要使用 Pramga: no-cache，相当于 Cache-Control： no-cache。例如：Pragma：no-cache
* 24.Proxy-Authenticate： 代理服务器响应浏览器，要求其提供代理身份验证信息。Proxy-Authorization：浏览器响应代理服务器的身份验证请求，提供自己的身份信息。
* 25.Range：浏览器「比如 Flashget 多线程下载时」告诉 WEB 服务器自己想取对象的哪部分。例如：Range: bytes=1173546-
* 26.Referer：浏览器向 WEB 服务器表明自己是从哪个 网页/URL 获得/点击 当前请求中的网址/URL。例如：Referer: ```http://www.sina.com/```
* 27.Server: WEB 服务器表明自己是什么软件及版本等信息。例如：Server：Apache/2.0.61 「Unix」
* 28.User-Agent: 浏览器表明自己的身份「是哪种浏览器」。例如：User-Agent：Mozilla/5.0 「Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14」 Gecko/20080404 Firefox/2、0、0、14
* 29.Transfer-Encoding: WEB 服务器表明自己对本响应消息体「不是消息体里面的对象」作了怎样的编码，比如是否分块「chunked」。例如：Transfer-Encoding: chunked
* 30.Vary: WEB服务器用该头部的内容告诉 Cache 服务器，在什么条件下才能用本响应所返回的对象响应后续的请求。假如源WEB服务器在接到第一个请求消息时，其响应消息的头部为：Content- Encoding: gzip; 
Vary: Content-Encoding那么 Cache 服务器会分析后续请求消息的头部，检查其 Accept-Encoding，是否跟先前响应的 Vary 头部值一致，即是否使用相同的内容编码方法，这样就可以防止 Cache 服务器用自己 Cache 里面压缩后的实体响应给不具备解压能力的浏览器。
例如：Vary：Accept-Encoding
* 31.Via： 列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器，他们用什么协议「和版本」发送的请求。
当客户端请求到达第一个代理服务器时，该服务器会在自己发出的请求里面添 加 Via 头部，并填上自己的相关信息，当下一个代理服务器收到第一个代理服务器的请求时，会在自己发出的请求里面复制前一个代理服务器的请求的Via 头部，并把自己的相关信息加到后面，
以此类推，当 OCS 收到最后一个代理服务器的请求时，检查 Via 头部，就知道该请求所经过的路由。例如：Via：1.0 236.D0707195.sina.com.cn:80 「squid/2.6.STABLE13」

### 6.OSI协议、TCP/IP协议以及每层对应的协议

1、OSI七层模型

* OSI中的层 功能 TCP/IP协议族
* 应用层 文件传输，电子邮件，文件服务，虚拟终端 TFTP「69」，HTTP「80」，SNMP「161、trap162」，FTP「传输20、控制21」，SMTP「25」，DNS「53」，Telnet「23」
* 表示层 数据格式化，代码转换，数据加密 没有协议
* 会话层 解除或建立与别的接点的联系 没有协议
* 传输层 提供端对端的接口 TCP，UDP
* 网络层 为数据包选择路由 IP，ICMP「IP」，RIP「广播、UDP」，OSPF「组播、IP」，BGP「TCP」，IGMP「IP」
* 数据链路层 传输有地址的帧以及错误检测功能 SLIP，CSLIP，PPP，ARP，RARP，MTU
* 物理层 以二进制数据形式在物理媒体上传输数据 ISO2110，IEEE802，IEEE802.2

2、TCP/IP五层模型的协议

* 应用层
* 传输层 四层交换机、也有工作在四层的路由器
* 网络层 路由器、三层交换机
* 数据链路层 网桥「现已很少使用」、以太网交换机「二层交换机」、网卡「其实网卡是一半工作在物理层、一半工作在数据链路层」
* 物理层 中继器、集线器、还有我们通常说的双绞线也工作在物理层
* 对于只有四层的教科书，物理+链路=网络接口层

3、分组与分片

分组：传输层概念，分片：网络层概念

对于TCP：

因为TCP是可靠传输协议，如果要传输的数据大于 1480 - 20「TCP头部」 =1460Byte时，在IP层被分片，而IP层分片会导致，如果其中的某一个分片丢失，因为TCP层不知道哪个IP数据片丢失，所以
就需要重传整个数据段，这样就造成了很大空间和时间资源的浪费，为了解决这个问题，就有了TCP分组和MSS「最长报文大小」概念，利用TCP三次握手建立链接的过程，交互各自的
MTU，然后用小的那个MTU-20-20「MTU最大传输单元」 , 得到MSS，这样就避免在IP层被分片。

对于UDP：

由于UDP是不可靠传输的，所以IP分片主要是为了UDP服务的，所以就有了网上的
1500 - 20「IP头部」 - 8「UDP头部」 > 1472 的说法，把1472作为IP分片的标准

为什么需要减去20的头部是因为，计算机网络协议间传输数据的时候，过程是：

        组装：从应用层向下，每向下传输一层，就将打上该层的协议头部，以便识别该层数据。
        拆包：一旦数据由链路层传到应用层，也需要一层层的拆分，得到上层的协议头部，并得到该层对应的数据

所以数据在传输层，协议头部就是TCP的大小20字节「UDP 8字节」
如果此时数据向下传输，到达网络层，则协议头部实际上变成了40字节「此时是在TCP头部基础上打包的，所以需要增加TCP头部大小」。也就是网络层协议头是总计40字节，但是IP协议头部仍是20字节。

IP数据包分片后需要在目的地进行重组

路由的主要功能：存储、转发

路由的分组主要是对网络层IP数据包进行分发，具体步骤：

    1.提取IP数据报告首部中的目的IP地址
    2.判断目的IP地址所在的网络是否与本路由器直接相连。如果是，就直接交付给目的网洛：如果不是执行3
    3.检查路由器表中是否有目的IP地址的特定主机路由。如果有，按特定主机路由转发：如果没有，执行4
    4.逐条检查路由表。若找到匹配路由，则按照路由表进行转发：若所有路由均不匹配，则执行5
    5.若路由表中设置有默认路由，则按照默认路由表转发：否则，执行6
    6.向源主机报错
   
以下更加具体的协议：

![](../public/image/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE2.png)

![](../public/image/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE.png)

### 7.session机制、cookie机制 

1、Cookie与Session的区别

* cookie数据存放在客户的浏览器「客户端」上，session数据放在服务器上，但是服务端的session的实现对客户端的cookie有依赖关系的；
* cookie不是很安全，别人可以分析存放在本地的COOKIE并进行COOKIE欺骗，考虑到安全应当使用session；
* session会在一定时间内保存在服务器上。当访问增多，会比较占用你服务器的性能。考虑到减轻服务器性能方面，应当使用COOKIE；
* 单个cookie在客户端的限制是3K，就是说一个站点在客户端存放的COOKIE不能超过3K；「4k不到，chrome最大，个数一般50」
* 子域名可以访问父域名的cookie而父域名不可以访问子域名的cookie

2、虽然session依赖cookie实现，但这并不是绝对的

其他实现方法

* 基于URL Path Parameter 默认支持
* 基于Cookie 如果没用修改Context容器的标识，则默认也支持  
* 基于SSL 默认不支持，connector.getAttribute「"SSLEnabled"」为True是支持
* Context是tomcat架构中的容器之一，定义在host容器中，同时war包必须依赖host容器解析web.xml，而SpringBoot jar包不需要

补充：

* Connector是tomcat核心组件负责接受请求，也是容器的顶级父接口，所有容器必须实现Connector接口
* 容器：Tomcat>Container>Engine>Host>Context>Wrapper>Servlet 「Engine、Host是非必需，Wrapper是使用门面设计模式，安全暴露数据」
* 详情请阅读Tomcat架构设计相关书籍

### 8.TCP三次握手、四次挥手

1、三次握手

三次握手的目的是连接服务器指定端口，建立TCP连接，并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。在socket编程中，客户端执行connect「」时，将触发三次握手。

* 第一次：客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口，以及初始序号X，保存在包头的序列号「Sequence Number」字段里。
* 第二次：发回确认包「ACK」应答。即SYN标志位和ACK标志位均为1同时，将确认序号「Acknowledgement Number」设置为客户的ISN加1「初始序列号ISN是客户端随机产生的一个值」，即x+1。并发送一个自己的ISN「y」。
* 第三次：客户端发送确认包「ACK」 SYN标志位为0，ACK标志位为1，并且把服务器发来的ISN+1「y+1」作为确认号发送给对方，且序列号设置为第二次的确认号x+1

![](../public/image/%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B.jpg)

2、SYN攻击

在三次握手过程中，服务器发送SYN-ACK之后，收到客户端的ACK之前的TCP连接称为半连接「half-open connect」.此时服务器处于Syn_RECV状态.当收到ACK后，服务器转入ESTABLISHED状态<br>
Syn攻击就是 攻击客户端 在短时间内伪造大量不存在的IP地址，向服务器不断地发送syn包，服务器回复确认包，并等待客户的确认，由于源地址是不存在的，服务器需要不断的重发直至超时，这些伪造的SYN包将长时间占用未连接队列<br>
正常的SYN请求被丢弃，目标系统运行缓慢，严重者引起网络堵塞甚至系统瘫痪。Syn攻击是一个典型的DDOS攻击。<br>
检测SYN攻击非常的方便，当你在服务器上看到大量的半连接状态时，特别是源IP地址是随机的，基本上可以断定这是一次SYN攻击.在Linux下可以如下命令检测是否被Syn攻击<br>
netstat -n -p TCP | grep SYN_RECV 一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击，修改tcp协议实现。<br>
主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等。但是不能完全防范syn攻击。

3、四次挥手

由于TCP连接是全双工的，因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就只能发送一个FIN来终止这个方向的连接。<br>
收到一个 FIN只意味着这一方向上没有数据流动，一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭，而另一方执行被动关闭。

1. 客户端A发送一个FIN，用来关闭客户A到服务器B的数据传送，并发送一个自己的ISN「u」
2. 服务器B收到这个FIN，它发回一个ACK，确认序号为收到的序号加1「u+1」。和SYN一样，一个FIN将占用一个序号。同时发送一个自己的ISN「v」
3. 服务器B关闭与客户端A的连接，发送一个FIN、ACK给客户端A，确认号为收到的序号加1「u+1」，与上一次不变。同时发送一个自己的ISN「w」
4. 客户端A发送ACK报文确认，并将确认序号设置为收到序号加1「w1」，序列号就是上一次的确认号「u+1」

实际上无论是连接或者断开连接，每次主动的一方都需要先生成一个ISN作为初始序列号seq，然后接收端为了确认需要对seq进行+1，即变成确认号ack。
确认号表示下次需要响应端发送的数据的起始位置，因为确认号变成下次的起始序列号，以此来推断连接有效，当然这也是因为seq在被收到后会加1。
收到seq=w，应该响应并返回ack=w+1，收到ack=u+1，则表示下次发送序列号为seq=ack=u+1，应该响应并返回seq=u+1。

![](../public/image/TCP.JPG)

4、为什么建立连接协议是三次握手，而关闭连接却是四次握手呢

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后，它可以把ACK和SYN「ACK起应答作用，而SYN起同步作用」放在一个报文里来发送。<br>
但关闭连接时，当收到对方的FIN报文通知时，它仅仅表示对方没有数据发送给你了；但未必你所有的数据都全部发送给对方了，所以你可能未必会马上会关闭SOCKET<br>
也即你可能还需要发送一些数据给对方之后，再发送FIN报文给对方来表示你同意现在可以关闭连接了，所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

5、为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态？

如果 TIME_WAIT 状态保持时间不足够长「比如小于2MSL」，第一个连接就正常终止了。 第二个拥有相同相关五元组的连接出现，而第一个连接的重复报文到达，干扰了第二 个连接。
TCP实现必须防止某个连接的重复报文在连接终止后出现，所以让TIME_WAIT 状态保持时间足够长「2MSL」，连接相应方向上的TCP报文要么完全响应完毕，要么被 丢弃。
建立第二个连接的时候，不会混淆。

6、TIME_WAIT状态有两个存在的理由。

1.可靠的实现TCP全双工链接的终止。

这是因为虽然双方都同意关闭连接了，而且握手的4个报文也都协调和发送完毕，按理可以直接回到CLOSED状态「就好比从SYN_SEND状态到ESTABLISH状态那样」<br>
但是因为我们必须要假想网络是不可靠的，你无法保证你最后发送的ACK报文会一定被对方收到，因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文<br>
而重发FIN报文，所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

2.允许老的重复的分组在网络中消逝。

假 设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接，过一段时间后在 相同的IP地址和端口建立另一个连接。<br>
后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连 接已经终止后再现，从而被误解成属于同一链接的某一个新的化身。<br>
为做到这一点，TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然 TIME_WAIT状态的持续时间是MSL的2倍，这就足以让某个方向上的分组最多存活msl秒即被丢弃，另一个方向上的应答最多存活msl秒也被丢弃。<br>
 通过实施这个规则，我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。

7、为什么不能用两次握手进行连接？

我们知道，3次握手完成两个重要的功能，既要双方做好发送数据的准备工作「双方都知道彼此已准备好」，也要允许双方就初始序列号进行协商，这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手，死锁是可能发生的。作为例子，考虑计算机S和C之间的通信，假定C给S发送一个连接请求分组，S收到了这个分组，并发 送了确认应答分组。
按照两次握手的协定，S认为连接已经成功地建立了，可以开始发送数据分组。可是，C在S的应答分组在传输中被丢失的情况下，将不知道S 是否已准备好，不知道S建立什么样的序列号，C甚至怀疑S是否收到自己的连接请求分组。
在这种情况下，C认为连接还未建立成功，将忽略S发来的任何数据分 组，只等待连接确认应答分组。而S在发出的分组超时后，重复发送同样的分组。这样就形成了死锁。

补充：

1. 默认情况下「不改变socket选项」，当你调用close「 or closesocket，以下说close不再重复」时，如果发送缓冲中还有数据，TCP会继续把数据发送完。
2. 发送了FIN只是表示这端不能继续发送数据「应用层不能再调用send发送」，但是还可以接收数据。
3. 应用层如何知道对端关闭？通常，在最简单的阻塞模型中，当你调用recv时，如果返回0，则表示对端关闭。在这个时候通常的做法就是也调用close，那么TCP层就发送FIN，继续完成四次握手。
如果你不调用close，那么对端就会处于FIN_WAIT_2状态，而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。
4. 在很多时候，TCP连接的断开都会由TCP层自动进行，例如你CTRL+C终止你的程序，TCP连接依然会正常关闭，你可以写代码试试。

8、特别的TIME_WAIT状态

主动关闭的一方在发送完对对方FIN报文的确认「ACK」报文后，会进入TIME_WAIT状态。TIME_WAIT状态也称为2MSL状态。

1. 什么是2MSL？MSL即Maximum Segment Lifetime，也就是报文最大生存时间，引用《TCP/IP详解》中的话：“它「MSL」是任何报文段被丢弃前在网络内的最长时间。”
那么，2MSL也就是这个时间的2倍。其实我觉得没必要把这个MSL的确切含义搞明白，你所需要明白的是，当TCP连接完成四个报文段的交换时，主动关闭的一方将继续等待一定时间「2-4分钟」，即使两端的应用程序结束。
你可以写代码试试，然后用setstat查看下。
2. 为什么需要2MSL？根据《TCP/IP详解》和《The TCP/IP Guide》中的说法，有两个原因：

        
        其一，保证发送的ACK会成功发送到对方，如何保证？我觉得可能是通过超时计时器发送。这个就很难用代码演示了。
        其二，报文可能会被混淆，意思是说，其他时候的连接可能会被当作本次的连接。
        直接引用《The TCP/IP Guide》的说法：The second is to provide a “buffering period” between the end of this connection and 
        any subsequent ones. If not for this period， it is possible that packets from different connections could be mixed， creating confusion.

9、TIME_WAIT状态所带来的影响

当某个连接的一端处于TIME_WAIT状态时，该连接将不能再被使用。事实上，对于我们比较有现实意义的是，这个端口将不能再被使用。<br>
某个端口处于TIME_WAIT状态「其实应该是这个连接」时，这意味着这个TCP连接并没有断开「完全断开」，那么，如果你bind这个端口，就会失败。<br>
对于服务器而言，如果服务器突然crash掉了，那么它将无法再2MSL内重新启动，因为bind会失败。解决这个问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你可以重用一个地址。

10、对于TIME_WAIT的插曲

当建立一个TCP连接时，服务器端会继续用原有端口监听，同时用这个端口与客户端通信。而客户端默认情况下会使用一个随机端口与服务器端的监听端口通信。<br>
有时候，为了服务器端的安全性，我们需要对客户端进行验证，即限定某个IP某个特定端口的客户端。客户端可以使用bind来使用特定的端口。<br>
对于服务器端，当设置了SO_REUSEADDR选项时，它可以在2MSL内启动并listen成功。但是对于客户端，当使<br>
用bind并设置SO_REUSEADDR时，如果在2MSL内启动，虽然bind会成功，但是在windows平台上connect会失败。而在linux上则不存在这个问题。<br>
要解决windows平台的这个问题，可以设置SO_LINGER选项。SO_LINGER选项决定调用close时TCP的行为。<br>
SO_LINGER涉及到linger结构体，如果设置结构体中l_onoff为非0，l_linger为0，那么调用close时TCP连接会立刻断开，TCP不会将发送缓冲中未发送的数据发送，而是立即发送一个RST报文给对方<br>
这个时候TCP连接就不会进入TIME_WAIT状态。如你所见，这样做虽然解决了问题，但是并不安全。通过以上方式设置SO_LINGER状态，等同于设置SO_DONTLINGER状态。

11、断开连接时的意外

这个算不上断开连接时的意外，当TCP连接发生一些物理上的意外情况时，例如网线断开，linux上的TCP实现会依然认为该连接有效，而windows则会在一定时间后返回错误信息。
这似乎可以通过设置SO_KEEPALIVE选项来解决，不过不知道这个选项是否对于所有平台都有效。

12、 QQ使用什么协议？

UDP、TCP、OICQ 「可能还有P2P。。不讨论了」

OICQ底层是UDP

主要区分点：

1. 需要保证可靠性，较高的安全性、且对效率要求不是非常大，使用TCP、「HTTP、HTTPS」
2. 需要保证较高的效率、速度，且允许丢包，使用UDP
3. 需要效率、速度、一定的安全性，在上层对UDP数据报进行加密处理，使用自己的加密算法。

![wireshark](../public/image/QQ%20protocol.png)

对UDP进行封装、传输层以上使用自己的高层协议。

### 9.打开网页到页面显示之间的过程

1、DNS解析

* 浏览器首先搜索浏览器自身缓存的DNS记录。
* 如果浏览器缓存中没有找到需要的记录或记录已经过期，则搜索hosts文件和操作系统缓存。
* 如果在hosts文件和操作系统缓存中没有找到需要的记录或记录已经过期。
* 如果域名解析服务器也没有该域名的记录，则开始递归+迭代解析。
* 获取域名对应的IP后，一步步向上返回，直到返回给浏览器。

2、发起TCP请求

浏览器会选择一个大于1024的本机端口向目标IP地址的80端口发起TCP连接请求。经过标准的TCP握手流程，建立TCP连接。

3、发起HTTP请求

其本质是在建立起的TCP连接中，按照HTTP协议标准发送一个索要网页的请求。

4、负载均衡

什么是负载均衡？当一台服务器无法支持大量的用户访问时，将用户分摊到两个或多个服务器上的方法叫负载均衡。
什么是Nginx？Nginx是一款面向性能设计的HTTP服务器，相较于Apache、lighttpd具有占有内存少，稳定性高等优势。
负载均衡的方法很多，Nginx负载均衡、LVS-NAT、LVS-DR等。关于负载均衡的多种方法详情大家可以Google一下。
Nginx有4种类型的模块：core、handlers、filters、load-balancers。
我们这里讨论其中的2种，分别是负责负载均衡的模块load-balancers和负责执行一系列过滤操作的filters模块。


1. 一般，如果我们的平台配备了负载均衡的话，前一步DNS解析获得的IP地址应该是我们Nginx负载均衡服务器的IP地址。所以，我们的浏览器将我们的网页请求发送到了Nginx负载均衡服务器上。
2. Nginx根据我们设定的分配算法和规则，选择一台后端的真实Web服务器，与之建立TCP连接、并转发我们浏览器发出去的网页请求。
Nginx默认支持 RR轮转法 和 ip_hash法 这2种分配算法。前者会从头到尾一个个轮询所有Web服务器，而后者则对源IP使用hash函数确定应该转发到哪个Web服务器上，也能保证同一个IP的请求能发送到同一个Web服务器上实现会话粘连。
也有其他扩展分配算法，如：fair：这种算法会选择相应时间最短的Web服务器，url_hash：这种算法会使得相同的url发送到同一个Web服务器。
3. Web服务器收到请求，产生响应，并将网页发送给Nginx负载均衡服务器。
4. Nginx负载均衡服务器将网页传递给filters链处理，之后发回给我们的浏览器。
5. Filter的功能可以理解成先把前一步生成的结果处理一遍，再返回给浏览器。比如可以将前面没有压缩的网页用gzip压缩后再返回给浏览器。

5、浏览器渲染

* 浏览器根据页面内容，生成DOM Tree。根据CSS内容，生成CSS Rule Tree「规则树」。调用JS执行引擎执行JS代码。
* 根据DOM Tree和CSS Rule Tree生成Render Tree「呈现树」。
* 根据Render Tree渲染网页。但是在浏览器解析页面内容的时候，会发现页面引用了其他未加载的image、css文件、js文件等静态内容，因此开始了第二部分。

6、网页静态资源加载

### 10.HTTP和HTTPS区别，HTTPS在请求时额外的过程，HTTPS是如何保证数据安全的 

* SSL位于应用层于传输层TCP之间，原本数据由应用层直接交由传输层处理，现在会经过SSL加密再进行传输
* HTTPS要比HTTP更加安全一些，也就是说HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份验证的网络协议要比HTTP协议安全，现在大多数的网站都逐渐用HTTPS
* 因为安全问题太重要了，有很多的网站都被攻破了，用户数据被泄露。全站HTTPS将是以后网络发展的趋势，国外很多站点都是实行的全站HTTPS
* HTTP和HTTPS使用的是完全不同的连接方式，用的端口也不一样，前者是80，后者是443。同时由于加密解密需要消耗CPU等系统资源，所以HTTPS会更慢
* HTTPS协议需要到CA申请证书，一般需要额外支出，此外还有一点需要注意的是，无论HTTPS、HTTP、等其他协议，它们的端口虽然推荐标准有默认值且众所周知，
但是也带来了被攻击的危险性，实际上很多时候不会使用该端口，这在RFC2817有说明，实际也是这样的

[SSL与TLS最简洁概括](../other/SSLAndTls.md)

[RFC2818 - HTTP Over TLS](http://www.cnpaf.net/rfc/rfc2818.txt)

[RFC2817 - Upgrading to TLS Within HTTP/1.1 注意区别，此时还不是HTTPS](http://www.cnpaf.net/rfc/rfc2817.txt)


Sunyandong-CS补充：

1、HTTPS的具体过程

* 在使用HTTPS是需要保证服务端配置正确了对应的安全证书
* 客户端发送请求到服务端
* 服务端返回公钥和证书到客户端
* 客户端接收后会验证证书的安全性，如果通过则会随机生成一个随机数，用公钥对其加密，发送到服务端
* 服务端接受到这个加密后的随机数后会用私钥对其解密得到真正的随机数，随后用这个随机数当做私钥对需要发送的数据进行对称加密
* 客户端在接收到加密后的数据使用私钥「即生成的随机值」对数据进行解密并且解析数据呈现结果给客户
* SSL加密建立

2、中间人攻击 

HTTPS也不是绝对安全的，针对SSL的中间人攻击方式主要有两类，分别是SSL劫持攻击和SSL剥离攻击

SSL劫持攻击

* SSL劫持攻击即SSL证书欺骗攻击，攻击者为了获得HTTPS传输的明文数据，需要先将自己接入到客户端和目标网站之间；
在传输过程中伪造服务器的证书，将服务器的公钥替换成自己的公钥，这样，中间人就可以得到明文传输带Key1、Key2和Pre-Master-Key，从而窃取客户端和服务端的通信数据；
但是对于客户端来说，如果中间人伪造了证书，在校验证书过程中会提示证书错误，由用户选择继续操作还是返回，
由于大多数用户的安全意识不强，会选择继续操作，此时，中间人就可以获取浏览器和服务器之间的通信数据，如果客户端不信任，则这种攻击手段也无法发挥作用。

SSL剥离攻击

* 这种攻击方式也需要将攻击者设置为中间人，之后见HTTPS范文替换为HTTP返回给浏览器，而中间人和服务器之间仍然保持HTTPS服务器。
由于HTTP是明文传输的，所以中间人可以获取客户端和服务器传输数据

3、中间人攻击的预防

* 确保在URL前你所访问的网站有HTTPS
* 点击电子邮件前，检查电子邮件的发件人
* 如果你是一个网站管理员，你应当执行HSTS协议
* 不要在公共Wi-Fi网络上购买或发送敏感数据
* 确保你的网站没有任何混合内容
* 如果你的网站使用了SSL，确保你禁用了不安全的SSL/TLS协议。你应当只启用了TLS 1.1和TLS 1.2
* 不要点击恶意链接或电子邮件
* 不要下载盗版内容
* 将安全工具正确地安装在系统上

### 11.IP地址子网划分 

参考RFC:

http://www.cnpaf.net/rfc/rfc932.txt 

http://www.cnpaf.net/Class/RFC/200408/894.html  

这种不懂就看RFC

### 12.Post和Get请求的异同

POST和GET在编程中的区别

1. Get可提交的数据量较小「1024字节、2048字节...」、而Post提交的数据量较大「80kb、100kb...」，浏览器和服务器会有不同的限制。
2. 在ASP中，服务端获取GET请求参数用Request.QueryString，获取POST请求参数用Request.Form。
3. 在JSP中，用request.getParameter(\"XXXX\")来获取，虽然jsp中也有request.getQueryString()方法，但使用起来比较麻烦，比如：传一个test.jsp?name=hyddd&password=hyddd，用request.getQueryString()得到的是：name=hyddd&password=hyddd。
4. GET请求的数据会附在URL之后「就是把数据放置在HTTP协议头中」，以?分割URL和传输数据，参数之间以&相连。
5. POST把提交的数据则放置在是HTTP包的包体中。
6. 说Get是安全的指的仅仅是非修改信息，Get用于获取/查询资源信息，Post用于更新资源信息。
7. Post安全性比Get高，Get发出的URL请求将用户名密码明文显示出来；
8. GET是幂等的，POST不是
        
            
        会被浏览器缓存
        翻看浏览器的历史记录
        会造成Cross-site request forgery攻击

Sunyandong-CS的补充：

1、什么是幂等性？

HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。即：同一个请求，发送一次和发送N次效果是一样的！<br>
幂等的方法：GET、DELETE、PUT <br>
PUT与POST均是创建或更新，唯一不同是POST非幂等

[RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)

2、MAC 地址和 IP地址的区别，为什么网络连接使用IP地址而不是用MAC地址？
    
* IP地址「32bit」是指Internet协议使用的地址，而MAC地址「48bit」是Ethernet协议使用的地址。
* IP地址是可以自动分配的，MAC地址在每个网卡出场的时候就有一个全球唯一的MAC地址，所以很多的验证软件就是验证mac地址的。「忽略MAC伪造」
* IP是可以更改的，mac地址虽然也可以更改，但是一般用不上，除非要用来绕过一些验证软件的。网卡在通讯的时候通过mac地址相互识别。「忽略MAC伪造」
* IP地址的分配是基于网络拓朴，MAC地址的分配是基于制造商。
* IP地址应用于OSI第三层，即网络层，而MAC地址应用在OSI第二层，即数据链路层。

要想知道为什么网络连接使用IP，首先需要知道IP在此的作用是什么？

* 网络划分，区分不同网络
* 屏蔽不同厂商的标识，使得网络连接的细节对应用层来说是透明的。「应用层或上层不需要知道连接来自哪个厂商」
* 基于网络分层思想，更利于管理，寻错等。「使用统一的IP地址寻址、路由，但是对于不同的局域网IP，没必要让它们唯一，而如果没有IP，则与MAC通信地址必须写死，因为MAC不可变」

MAC地址一共有48bit，分为两部分，前24bit是厂商代码，后24bit是厂家自己分配的。
假如我们认为MAC地址可以区分不同的网络的话，那只能是使用厂商代码来区分不同的网络，也就是说使用同一个厂商生产的网卡的主机或者网络设备，
就是属于同一个网络。举个例子，比如说企业A使用了思科的网络设备，企业B也使用了思科的网络设备，那这两家企业就属于同一个网络了。
现实中这种情况是不可能的。
    
### 13.DNS解析过程

访问www.baidu.com

 * 本机向local dns请求www.baidu.com
 * local dns向根域请求www.baidu.com，根域返回com.域的服务器IP
 * 向com.域请求www.baidu.com，com.域返回baidu.com域的服务器IP
 * 向baidu.com请求www.baidu.com，返回cname ```www.a.shifen.com```和```a.shifen.com```域的服务器IP
 * 向root域请求www.a.shifen.com
 * 向com.域请求www.a.shife.com
 * 向shifen.com请求
 * 向a.shifen.com域请求
 * 拿到www.a.shifen.com的IP
 * localdns返回本机www.baidu.com cname ```www.a.shifen.com``` 以及 ```www.a.shifen.com```的IP

实际步骤：

* 1.浏览器先检查自身缓存中有没有被解析过的这个域名对应的ip地址，如果有，解析结束。同时域名被缓存的时间也可通过TTL属性来设置。
* 2.如果浏览器缓存中没有「专业点叫还没命中」，浏览器会检查操作系统缓存中有没有对应的已解析过的结果。
而操作系统也有一个域名解析的过程。在windows中可通过c盘里一个叫hosts的文件来设置，如果你在这里指定了一个域名对应的ip地址，那浏览器会首先使用这个ip地址。
但是这种操作系统级别的域名解析规程也被很多黑客利用，通过修改你的hosts文件里的内容把特定的域名解析到他指定的ip地址上，造成所谓的域名劫持。
所以在windows7中将hosts文件设置成了readonly，防止被恶意篡改。
* 3.如果至此还没有命中域名，才会真正的请求本地域名服务器「LDNS」来解析这个域名，这台服务器一般在你的城市的某个角落，距离你不会很远，并且这台服务器的性能都很好，一般都会缓存域名解析结果，大约80%的域名解析到这里就完成了。
* 4.如果LDNS仍然没有命中，就直接跳到Root Server 域名服务器请求解析
* 5.根域名服务器返回给LDNS一个所查询域的主域名服务器「gTLD Server，国际顶尖域名服务器，如.com .cn .org等」地址
* 6.此时LDNS再发送请求给上一步返回的gTLD
* 7.接受请求的gTLD查找并返回这个域名对应的Name Server的地址，这个Name Server就是网站注册的域名服务器「阿里云，腾讯云等」
* 8.Name Server根据映射关系表找到目标ip，返回给LDNS
* 9.LDNS缓存这个域名和对应的ip
* 10.LDNS把解析的结果返回给用户，用户根据TTL值缓存到本地系统缓存中，域名解析过程至此结束

所谓 递归查询过程 就是 “查询的递交者” 更替， 而 迭代查询过程 则是 “查询的递交者”不变。

    1.递归查询 服务器帮客户端请求
    递归查询是一种DNS 服务器的查询模式，在该模式下DNS 服务器接收到客户机请求，必须使用一个准确的查询结果回复客户机。
    如果DNS 服务器本地没有存储查询DNS 信息，那么该服务器会询问其他服务器，并将返回的查询结果提交给客户机。
    2.迭代查询 还是客户端去请求
    DNS 服务器另外一种查询方式为迭代查询，DNS 服务器会向客户机提供其他能够解析查询请求的DNS 服务器地址，当客户机发送查询请求时
    DNS 服务器并不直接回复查询结果，而是告诉客户机另一台DNS 服务器地址，客户机再向这台DNS 服务器提交请求，依次循环直到返回查询的结果
    为止。

### 14. TCP如何保证数据的可靠传输的

1、四种TCP拥塞控制算法 RFC2581 http://www.cnpaf.net/Class/RFC/200408/1000.html
        
慢启动

拥塞避免

快速重传
 
[快速恢复](http://www.cnpaf.net/Class/RFC/200408/1001.html)

2、流量控制 没找到RFC版本

ARQ 自动重传请求「Automatic Repeat-reQuest，ARQ」是OSI模型中运输层的错误纠正协议之一。
它包括停止等待ARQ协议和连续ARQ协议，错误侦测「Error Detection」、正面确认「Positive Acknowledgment」、逾时重传「Retransmission after Timeout」与负面确认继以重传「Negative Acknowledgment and Retransmission」等机制

停止等待ARQ

一、解释

停止等待协议「stop-and-wait」是最简单但也是最基础的数据链路层协议。

二、要点

只有收到序号正确的确认帧ACKn后，才更新发送状态变量V「S」一次，并发送新的数据帧。
接收端接收到数据帧时，就要将发送序号N「S」 与本地的接收状态变量V「R」 相比较。
若二者相等就表明是新的数据帧，就收下，并发送确认。
否则为重复帧，就必须丢弃。但这时仍须向发送端发送确认帧ACKn，而接收状态变量V「R」 和确认序号n 都不变。
连续出现相同发送序号的数据帧，表明发送端进行了超时重传。连续出现相同序号的确认帧，表明接收端收到了重复帧。
发送端在发送完数据帧时，必须在其发送缓存中暂时保留这个数据帧的副本。这样才能在出差错时进行重传。只有确认对方已经收到这个数据帧时，才可以清除这个副本。
实用的CRC 检验器都是用硬件完成的。CRC 检验器能够自动丢弃检测到的出错帧。因此所谓的“丢弃出错帧”，对上层软件或用户来说都是感觉不到的。
发送端对出错的数据帧进行重传是自动进行的，因而这种差错控制体制常简称为ARQ「Automatic Repeat reQuest」，直译是自动重传请求，但意思是自动请求重传。

连续ARQ “GBN”

所谓连续就是在发送完一个数据帧后，不是停下来等待确认帧，而是可以连续再发若干帧，边发可以边等待确认帧，如果收到了确认帧，又可以继续发送数据帧，
由于减少了等待的时间，利用率就提高了。但是连续ARQ在收到一个否认帧或超时后，所有该帧后面的帧都要重发而不管该帧后面的帧是否正确传送
于是便有了选择重传ARQ协议。
    
选择重传ARQ

所谓选择就是指只选择错误的帧进行重发，而不像连续ARQ那样所有该错误帧后面的帧都要重发。但是选择重传ARQ是以浪费存储空间来提高信道的利用率的，因为只是选择性地重发错误帧
那么后面的帧就有可能比前面的帧先到达接收端，这个时候如果一收到帧就往上传用户就有可能收到不正确的帧，例如A向B发送“我是A”，但是B很有可能收到这样的信息“是A我”
为了避免这样的错误，在接收方就必须先将A发过来的信息保存起来，直到所有信息均到达后再对其进行组装，组装完成后再往上传，这样就浪费了存储空间

滑动窗口协议，也称为回退N步协议「Go-Back-N，GBN」中，允许发送方发送多个分组「当有多个分组可用时」而不需等待确认，但它受限于在流水线 中为未确认的分组数不能超过某个最大允许数N。
滑动窗口协议是TCP使用的一种流量控制方法，此协议能够加速数据的传输，是连续ARQ协议。

     1.只有在接收窗口向前滑动时「与此同时也发送了确认」，发送窗口才有可能向前滑动。
     2.收发两端的窗口按照以上规律不断地向前滑动，因此这种协议又称为滑动窗口协议。
     3.当发送窗口和接收窗口的大小都等于1时，就是停止等待协议。
     4.当发送窗口大于1，接收窗口等于1时，就是回退N步协议。       
     5.当发送窗口和接收窗口的大小均大于1时，就是选择重传协议。
     6.协议中规定，对于窗口内未经确认的分组需要重传。
     
     这种分组的数量最多可以等于发送窗口的大小，即滑动窗口的大小n减去1「因为发送窗口不可能大于「n-1」，起码接收窗口要大于等于1」。

3、为何快速重传是选择3次ACK？

主要的考虑还是要区分包的丢失是由于链路故障还是乱序等其他因素引发。

两次duplicated ACK时很可能是乱序造成的！三次duplicated ACK时很可能是丢包造成
的！四次duplicated ACK更更更可能是丢包造成的！但是这样的响应策略太慢。丢包肯定会造成三次duplicated ACK！
综上是选择收到三个重复确认时窗口减半效果最好，这是实践经验。

在没有fast retransmit「快速重传」 / recovery「恢复」 算法之前，重传依靠发送方的retransmit timeout「超时重传」，就是在timeout内如果没有接收到对方的ACK，默认包丢了，发送方就重传，包的丢失原因
        
    1.包checksum「校检和」 出错 
    2.网络拥塞 
    3.网络断开，包括路由收敛
        
但是发送方无法判断是哪一种情况，于是采用最笨的办法，就是将自己的发送速率减半，即CWND 减为1/2，这样的方法对2是有效的，可以缓解网络拥塞，3则无所谓，反正网络断了，无论发
快发慢都会被丢；但对于1来说，丢包是因为偶尔的出错引起，一丢包就对半减速不合理。于是有了fast retransmit 算法，基于在反向还可以接收到ACK，可以认为网络并没
有断开，否则也接收不到ACK，如果在timeout 时间内没有接收到> 2 的duplicated ACK，则概率大事件为乱序，乱序无需重传，接收方会进行排序工作；而如果接收到三个或三
个以上的duplicated ACK，则大概率是丢包，可以逻辑推理，发送方可以接收ACK，则网络是通的，可能是1、2造成的，先不降速，重传一次，如果接收到正确的ACK，则一
切OK，流速依然「包出错被丢」。而如果依然接收到duplicated ACK，则认为是网络拥塞造成的，此时降速则比较合理。

### 15.地址解析协议ARP RARP

[RARP反向地址解析协议](http://www.cnpaf.net/rfc/rfc903.txt)

[ARP地址解析协议](https://tools.ietf.org/html/rfc826)

### 16.交换机和路由器的区别

* 「1」外形上：
       从外形上我们区分两者，交换机通常端口比较多看起来比较笨重，而路由器的端口就少得多体积也小得多，实际上右图并不是真正的路由器只是集成了路由器的功能，除此之外还有交换机的功能「LAN口就是作为交换机的端口来使用，WAN是用于连接外网的端口」，而两个天线则是无线AP接入点「即是通常所说的无线局域网wifi」。

* 「2」工作层次不同：
       最初的交换机工作在OSI开放式系统互联模型的数据链路层，也就是第二层，而路由器则工作在OSI模型的网络层，就是第三层。也就是由于这一点所以交换机的原理比较简单，一般都是采用硬件电路实现数据帧的转发，而路由器工作在网络层，肩负着网络互联的重任，要实现更加复杂的协议，具有更加智能的转发决策功能，一般都会在在路由器中跑操作系统，实现复杂的路由算法，更偏向于软件实现其功能。

* 「3」数据的转发对象不同：
        交换机是根据MAC地址转发数据帧，而路由器则是根据IP地址来转发IP数据报/分组。数据帧是在IP数据包/分组的基础上封装了帧头「源MAC和目的MAC等」和帧尾「CRC校验码」。而对于MAC地址和IP地址大家也许就搞不明白了，为何需要两个地址，实际上IP地址决定最终数据包要到达某一台主机，而MAC地址则是决定下一跳将要交互给哪一台设备「一般是路由器或主机」。而且，IP地址是软件实现的，可以描述主机所在的网络，MAC地址是硬件实现的，每一个网卡在出厂的时候都会将全世界唯一的MAC地址固化在网卡的ROM中，所以MAC地址是不能被修改的，但是IP地址是可以被网络管理人员配置修改的。

* 「4」"分工"不同
        交换机主要是用于组建局域网，而路由器则是负责让主机连接外网。多台主机可以通过网线连接到交换机，这时就组建好了局域网，就可以将数据发送给局域网中的其他主机，如我们使用的飞秋、极域电子教室等局域网软件就是通过交换机把数据转发给其他主机的，当然像极域电子教室这样的广播软件是利用广播技术让所有的主机都收到数据的。然而，通过交换机组建的局域网是不能访问外网的「即是Internet」，这时需要路由器来为我们”打开外面精彩世界的大门“，局域网的所有主机使用的都是私网的IP，所以必须通过路由器转化为公网的IP之后才能访问外网。

* 「5」冲突域和广播域
        交换机分割冲突域，但是不分割广播域，而路由器分割广播域。由交换机连接的网段仍属于同一个广播域，广播数据包会在交换机连接的所有网段上传播，在这种情况下会导致广播风暴和安全漏洞问题。而连接在路由器上的网段会被分配不通的广播域，路由器不会转发广播数据。需要说明的是单播的数据包在局域网中会被交换机唯一地送往目标主机，其他主机不会接收到数据，这是区别于原始的集线器的，数据的到达时间由交换机的转发速率决定，交换机会转发广播数据给局域网中的所有主机。
        最后需要说明的是：路由器一般有防火墙的功能，能够对一些网络数据包选择性过滤。现在的一些路由器都具备交换机的功能，一些交换机具备路由器的功能，被称为3层交换机，广泛使用。相比较而言，路由器的功能较交换机要强大，但是速度也较慢，价格昂贵，三层交换机既有交换机的线性转发报文的能力，又有路由器的良好的路由功能因此得到广泛的使用。
        当然关于路由器和交换机的一些介绍远不止这些，上述所说是主要的一些区别，同时也是本人对路由器和交换机的浅显认识，如有其他一些较明显的区别特征望给出宝贵意见。

### 17.HTTP/1.x 与HTTP/2.0区别

1、HTTP/1.x 的缺陷

HTTP/1.x 实现简单是以牺牲应用性能为代价的：

    客户端需要使用多个连接才能实现并发和缩短延迟；
    不会压缩请求和响应首部，从而导致不必要的网络流量；
    不支持有效的资源优先级，致使底层 TCP 连接的利用率低下。

2、采用二进制分帧层

HTTP/2.0所有通信都是在一个TCP连接上完成。
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧，它们都是二进制格式的，而在HTTP/1.X虽然分为请求头+请求体，但是属于一帧。

在通信过程中，只会有一个 TCP 连接存在，它承载了任意数量的双向数据流「Stream」。
一个数据流都有一个唯一标识符和可选的优先级信息，用于承载双向信息。
消息「Message」是与逻辑请求或响应消息对应的完整的一系列帧。
帧「Fram」是最小的通信单位，来自不同数据流的帧可以交错发送，然后再根据每个帧头的数据流标识符重新组装。

同时，单链接多资源的方式，使到至上而下的层面都得到了好处：

* 可以减少服务链接压力，内存占用少了，连接吞吐量大了
* 由于 TCP 连接减少而使网络拥塞状况得以改观;
* 慢启动时间减少，拥塞和丢包恢复速度更快。
也就是说，“资源合并减少请求”的优化手段对于HTTP2.0来说是没有效果的，只会增大无用的工作量而已。

把 HTTP 消息分解为独立的帧，交错发送，然后在另一端重新组装是 HTTP 2.0 最 重要的一项增强。<br>
事实上，这个机制会在整个 Web 技术栈中引发一系列连锁反应， 从而带来巨大的性能提升，因为：

* 可以并行交错地发送请求，请求之间互不影响;
* 可以并行交错地发送响应，响应之间互不干扰;
* 只使用一个连接即可并行发送多个请求和响应;
* 消除不必要的延迟，从而减少页面加载的时间;

那么也就是说“域名分区”这种优化手段对于HTTP2.0是无用的，因为资源都是并行交错发送，且没有限制，不需要额外的多域名并行下载。

3、支持服务端推送

HTTP/2.0 在客户端请求一个资源时，会把相关的资源一起发送给客户端，客户端就不需要再次发起请求了。例如客户端请求 page.html 页面，服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。

4、HTTP/2.0与Websocket区别

WebSocket是基于HTTP1.1的协议，可以简单理解为创建了一条TCP连接，在JS中用new WebSocket「"ws://hostname/chattingrom/"」
来创建，具有双向传输二进制等特性。而HTTP2.0则是对HTML、CSS等JS资源的传输方式进行了优化，并没有提供新的JS API，也不能用于实时传输消息。如果需要实时传输消息，现在还是需要SSE、WebSocket。现在的WebSocket还不能用于HTTP2.0的链路上。协议还在设计。draft-hirano-httpbis-websocket-over-http2-01 - WebSocket over HTTP/2draft-svirid-websocket2-over-http2-00 - WebSocket2 over HTTP/2

    作者：匿名用户
    链接：https://www.zhihu.com/question/32039008/answer/149333890
    来源：知乎
    著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。

5、采用首部压缩

HTTP/1.1 的首部带有大量信息，而且每次都要重复发送。
HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表，从而避免了重复传输。
不仅如此，HTTP/2.0 也使用 Huffman编码对首部字段进行压缩。

6、支持请求优先级

每个HTTP2.0流里面有个优先值，这个优先值确定着客户端和服务器处理不同的流采取不同的优先级策略，高优先级的流都应该优先发送，但又不会绝对的。绝对地准守，可能又会引入首队阻塞的问题：高优先级的请求慢导致阻塞其他资源交付。分配处理资源和客户端与服务器间的带宽，不同优先级的混合也是必须的。

7、Huffman 编码

霍夫曼树又称最优二叉树，是一种带权路径长度最短的二叉树。所谓树的带权路径长度，就是树中所有的叶结点的权值乘上其到根结点的路径长度「若根结点为0层，叶结点到根结点的路径长度为叶结点的层数」。树的路径长度是从树根到每一结点的路径长度之和，记为WPL=（W1*L1+W2*L2+W3*L3+...+Wn*Ln），N个权值Wi（i=1，2，...n）构成一棵有N个叶结点的二叉树，相应的叶结点的路径长度为Li（i=1，2，...n）。可以证明霍夫曼树的WPL是最小的。
[wikipedia Huffman Coding ](https://zh.wikipedia.org/wiki/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81)

例如：已知字符ababaabc [a:4，b:3，c:1]<br>
对于abc出现的频率进行排序得到list[1，3，4]，每次选取列表前两个相加，产生新的值，并将新的值加入list并排序，对下一个元素重复以上过程，直至list中所有元素均使用，得到一颗二叉树

进行编码

* 1.给霍夫曼树的所有左链接'0'与右链接'1'
* 2.从树根至树叶依序记录所有字母的编码

更为详细的请参考[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)](https://www.baidu.com/link?url=_asYT1RCe2xsyxwASlOZIacBVsHvELcl1xtCRZ2XG_SpXMTcKmhdtMOnV0YXw3Dn&wd=&eqid=a307227f00045eb6000000065b6addc1)

### 18.OAuth2.0协议 ###

1、OAuth 2.0是什么？

OAuth2.0是OAuth协议的延续版本，但不向后兼容OAuth 1.0即完全废止了OAuth1.0。 OAuth 2.0关注客户端开发者的简易性。
要么通过组织在资源拥有者和HTTP服务商之间的被批准的交互动作代表用户，要么允许第三方应用代表用户获得访问的权限。
同时为Web应用，桌面应用和手机，和起居室设备提供专门的认证流程。2012年10月，OAuth 2.0协议正式发布为RFC 6749。

oauth2.0提供了四种授权模式，开发者可以根据自己的业务情况自由选择。

使用场景

* 授权码授权模式「Authorization Code Grant」

    
        授权码模式是最常见的一种授权模式，在oauth2.0内是最安全和最完善的。
        适用于所有有Server端的应用，如Web站点、有Server端的手机客户端。 
        可以得到较长期限授权。

* 隐式授权模式「Implicit Grant」


        适用于所有无Server端配合的应用
        如手机/桌面客户端程序、浏览器插件。
        基于JavaScript等脚本客户端脚本语言实现的应用。

* 密码授权模式「Resource Owner Password Credentials Grant」
    
    
        这种模式适用于用户对应用程序高度信任的情况。比如是用户操作系统的一部分。
        认证服务器只有在其他授权模式无法执行的情况下，才能考虑使用这种模式。

* 客户端凭证授权模式「Client Credentials Grant」
    
    
        客户端模式应用于应用程序想要以自己的名义与授权服务器以及资源服务器进行互动。
        例如使用了第三方的静态文件服务

2、传统认证缺陷

在传统的client-server认证模型中，客户端请求访问服务器上受限的资源「protected resource」，需要通过使用资源所有者「resource owner」的凭证在服务器上进行认证。
为了支持第三方应用程序访问受限资源，资源所有者需要向第三方应用共享其凭证。这就会造成以下问题：

* 第三方应用为了后续使用，会存储资源所有者的凭证主要是密码。
* 服务端需要支持密码认证，尽管密码认证不安全。
* 第三方应用获得对资源的过度访问而不仅局限于受限资源，且资源所有者没有办法对其进行限制。
* 资源所有者无法收回权限，除非修改密码。
* 如果第三方应用的密码被破解，就会导致所有被该密码保护的数据被泄露。

3、OAuth 2.0授权流程

角色

* Client：需要授权的客户端
* Resource Owner：资源所有者
* Authorization Server：认证服务器
* Resource Server：资源服务器

授权码「Authorization Code」：相当于授权服务器口头告诉应用「网站、APP」，用户同意授权使用他的QQ登录该站点了。
令牌「Access Token」：相当于临时身份证。站点需要根据授权码再次向认证服务器申请令牌

* 第一步：引导用户到认证服务器
* 第二步：用户同意为第三方客户端授权
* 第三步：使用授权码向认证服务器申请令牌
* 第四步：向资源服务器申请资源
* 第五步：令牌延期「刷新」

![](../public/image/OAuth2.0.png)

4、OAuth2.0与SSO比较？

SSO是为了解决一个用户在鉴权服务器登陆过一次以后，可以在任何应用中畅通无阻，一次登陆，
多系统访问，操作用户是实打实的该应用的官方用户，用户的权限和分域以鉴权服务器的存储为准。

OAuth2.0解决的是通过令牌获取某个系统的操作权限，因为有clientId的标识，一次登陆只能对该系统生效，
第三方应用的操作用户不是鉴权系统的官方用户，授权权限鉴权中心可以做限制。

根本是两回事。


### 19.TCP/Socket/HTTP 长连接和短连接的区别与应用 ###

短连接

    连接->传输数据->关闭连接 
    HTTP是无状态的，浏览器和服务器每进行一次HTTP操作，就建立一次连接，但任务结束就中断连接。 
    也可以这样说：短连接是指SOCKET连接后发送后接收完数据后马上断开连接。 

长连接

    连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。 
    长连接指建立SOCKET连接后不管是否使用都保持连接，但安全性较差。 
    
    
HTTP的长连接

HTTP也可以建立长连接的，使用Connection:keep-alive，HTTP 1.1默认进行持久连接。HTTP1.1和HTTP1.0相比较而言，
最大的区别就是增加了持久连接支持「貌似最新的 http1.0 可以显示的指定 keep-alive」,但还是无状态的，或者说是不可以信任的。

什么时候用长连接，短连接？

长连接多用于操作频繁，点对点的通讯，而且连接数不能太多情况，。每个TCP连接都需要三步握手，这需要时间，如果每个操作都是先连接，再操作的话那么处理速度会降低很多，所以每个操作完后都不断开，次处理时直接发送数据包就OK了，不用建立TCP连接。
例如：数据库的连接用长连接， 如果用短连接频繁的通信会造成socket错误，而且频繁的socket 创建也是对资源的浪费。 

而像WEB网站的http服务一般都用短链接，因为长连接对于服务端来说会耗费一定的资源，而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源，如果用长连接，而且同时有成千上万的用户，如果每个用户都占用一个连接的话，那可想而知吧。
所以并发量大，但每个用户无需频繁操作情况下需用短连好。 

### 20.RFC部分文档号

TCP/IP包括很多个协议 下面是TCP/IP 协议和支持服务所支持的 RFC。

* 768 用户数据报协议 「UDP」
* 783 日常文件传输协议 「TFTP」
* 791 Internet 协议 「IP」
* 792 Internet 控制消息协议 「ICMP」
* 793 传输控制协议 「TCP」
* 816 故障隔离和恢复
* 826 地址解析协议 「ARP」
* 854 Telnet 协议 「TELNET」
* 862 回应协议 「ECHO」
* 863 放弃协议 「DISCARD」
* 864 字符生成器协议 「CHARGEN」
* 865 当日报价协议 「QUOTE」
* 867 白天协议 「DAYTIME」
* 894 基于 Ethernet 的 IP
* 919 广播 Internet 数据报
* 922 在现有子网中广播 Internet 数据报
* 950 Internet 标准子网化过程
* 959 文件传输协议 「FTP」
* 1001 TCP/UDP 传输上的 NetBIOS 服务的协议标准：概念和方法
* 1002 TCP/UDP 传输上的 NetBIOS 服务的协议标准：详细规范
* 1009 Internet 网关的要求
* 1034 域名 - 概念和工具
* 1035 域名 - 实现和规范
* 1042 基于令牌环的 IP
* 1055 通过串行线路的非标准 IP 数据报传输：SLIP
* 1065 有关基于 TCP/IP 的 Internet 的管理信息的结构和标识
* 1112 Internet 组管理协议 「IGMP」
* 1122 Internet 主机 - 通讯层的要求
* 1123 Internet 主机 - 应用和支持的要求
* 1144 对于低速串行链接压缩 TCP/IP 头
* 1157 简单网络管理协议 「SNMP」
* 1179 行式打印机监控程序协议
* 1188 FDDI 上的 IP
* 1191 路径 MTU 发现
* 1201 基于 ARCNET 的 IP
* 1256 ICMP 路由器发现消息
* 1323 高性能 TCP 扩展件
* 1332 PPP IP 控制协议 「IPCP」
* 1518 带有 CIDR 的 IP 地址分配的体系结构
* 1519 无类的域间路由 「CIDR」：地址分配和集合策略
* 1534 DHCP 和 BOOTP 之间的交互
* 1542 Bootstrap 协议的说明和扩展
* 1552 PPP 网际数据包交换控制协议 「IPXCP」
* 1661 点对点协议 「PPP」
* 1662 HDLC 帧中的 PPP
* 1748 使用 SMIv2 的 IEEE 802.5 MIB
* 1749 使用 SMIv2 的 IEEE 802.5 站源路由 MIB
* 1812 IP 版本 4 的要求路由器
* 1828 使用 Keyed MD5 的 IP 身份验证
* 1829 ESP DES-CBC 变换
* 1851 ESP 三重 DES-CBC 变换
* 1852 使用 Keyed SHA 的 IP 身份验证
* 1878 IPv4 的可变长度子网表
* 1886 支持 IP 版本 6 的 DNS 扩展名
* 1994 PPP 质询握手身份验证协议 「CHAP」
* 1995 DNS 中的增量区域传输
* 1996 用来提示 DNS 通知区域更改的机制
* 2018 TCP 选择的确认选项
* 2085 使用重播防止的 HMAC-MD5 IP 身份验证
* 2104 HMAC：邮件身份验证的键控哈希计算
* 2131 动态主机配置协议 「DHCP」
* 2136 域名系统中的动态更新 「DNS UPDATE」
* 2181 对 DNS 规范的说明
* 2236 网际分组管理协议 「IGMP」 版本 2
* 2308 DNS 查询的反向缓存 「DNS NCACHE」
* 2401 Internet 协议的“安全结构”
* 2402 IP 验证标头
* 2406 IP 封装安全措施负载量 「ESP」
* 2581 TCP 拥塞控制