🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
![](https://img.kancloud.cn/e9/90/e990d6fd5909fd3be3c6984d0ee35c55_700x289.jpg) ![](https://img.kancloud.cn/2a/fc/2afc31ad92e05f832a24acade967860a_699x336.png)![](https://img.kancloud.cn/8e/e7/8ee7b559881e1b8b3e44c79b4a33be6a_674x360.png) 1、三次握手四次挥手过程? ## 简述 TCP 三次握手? * 第一次握手:建立连接时,客户端发送syn包到服务器,并进入SYN_SENT状态,等待服务器确认 * 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; * 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态 服务器收到确认报文段之后,也进入已建立连接状态 ## 简述TCP 四次挥手? * 客户端应用进程发出连接释放报文段,并停止再发送数据,进入 FIN-WAIT-1(终止等待1)状态,等待服务器确认 * 服务器收到连接释放报文段后即发出确认,进入 CLOSE-WAIT(关闭等待)状态,服务器若发送数据,客户端扔要接收 * 客户端收到来自服务器的确认后,进入 FIN-WAIT-2(终止等待2)状态,等待服务器发出连接释放报文段 * 服务器没有要发送的数据,发出连接释放报文段,进入 LAST-ACK(最后确认)状态,等待客户端确认 * 客户端收到连接释放报文段后,发出确认,进入 TIME-WAIT(时间等待)状态,经过时间等待计时器设置的时间 2MSL 后,进入 CLOSED(关闭) 状态 * 服务器收到客户端报文段后,进入 CLOSED 状态 2、为什么不能两次握手、或者3次挥手 ## 为什么TCP建立连接握手是3次,挥手需要4次? 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。 ### 为什么不能用两次握手进行连接? 答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。 现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。 ## 3、udp和tcp的区别?特点? ![](https://img.kancloud.cn/b5/4d/b54d294d55e6c44cf11d35cd0e96f163_963x589.png) ### UDP 的主要特点 * UDP 是`无连接的`,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的时延 * UDP 使用`尽最大努力交付`,即不保证可靠交付,主机不需要维持复杂的连接状态表 * UDP 是`面向报文`的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是`保留这些报文的边界` * UDP`没有拥塞控制`,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的 * UDP 支持一对一、一对多、多对一和多对多的交互通信 * UDP 的`首部开销小`,只有8个字节,比 TCP 的20个字节的首部要短 ### TCP 的主要特点 * TCP 是`面向连接的运输层协议`。应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接 * 每一条 TCP 连接只能有两个`端点`,每一条 TCP 连接只能是`点对点`的(一对一) * TCP 提供`可靠交付`的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达 * TCP 提供`全双工通信`。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据 * `面向字节流`。TCP 中的“流”指的是`流入到进程或从进程流出的字节序列 4、websocke是怎么建立连接的,升级请求包含哪些内容? 1. Client发送一个 ‘upgrade' request,这是一个http请求,使用的是http协议。 2. Server返回一个http 101,代表请求成功。 5、http协议一次请求包含哪些内容?(请求头) ## 6、http和https的区别?https的加密方式? * https协议需要到CA(Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。 * http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。 * http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 * http的连接很简单,是无状态的。Https协议是由SSL+Http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。) ## 7、一次网页输入地址到展示的完整过程? 0、浏览器本地缓存匹配; 1、本地hosts映射对比; 2、本地dns缓存解析; 3、远程dns解析获得服务器ip地址; 4、浏览器发送tcp连接请求包(syn); 5、请求包经过传输层、网络层、数据链路层封装通过网卡到达路由器; 6、路由器转发数据包到所属运营商服务器; 7、运营商服务器通过寻址最短路径通过中继节点到达指定ip地址; 8、服务器端可能存在反向代理或者负载均衡,都是直接转发请求至上游服务器,当然也可以制定安全防御规则直接丢弃请求包; 9、上游服务器收到连接请求,在自身可用的情况下,返回(syn+ack); 10、浏览器校验ack,再次发送(syn+ack); 11、服务器校验ack切换连接状态至established,然后根据请求传输数据包; 12、当transform-encoding为chunked时,浏览器开始渲染页面; 13、四次挥手,连接关闭; 14、渲染数据完成。 ## 8、get和post的区别? 1. get 请求一般用于向服务端获取数据,post 一般向服务端提交数据 2. get 传输的参数在 url 中,传递参数大小有限制,post 没有大小限制, 3. get 不安全,post 安全性比get高 4. get请求在服务端用Request.queryString 接受 ,post 请求在服务端用Requset.form 接受 5. get是两段提交,先是返回100,之后再提交返回200,post直接就是200 ## 9、网络七层模型和五大网络io模型?(各部分包含什么协议和作用) ![](https://img.kancloud.cn/55/02/5502382c635ec08473e8472368674f02_855x252.png) * 应用层:应用层协议定义的是应用进程间通信和交互的规则 * 运输层:运输层的任务就是负责向`两台主机中进程之间的通信`提供`通用的数据传输`服务 * 网络层:把运输层产生的报文段或用户数据报封装成`分组`或`包`进行传送 * 数据链路层:将网络层交下来的 IP 数据报组装成帧,并在两个相邻结点间的链路上传送 * 物理层:利用物理媒体以`比特`形式传送数据 ## 10、http的常见状态码?代表什么?怎么解决? 200(成功)服务器已成功处理了请求。 301(永久移动) 302(临时移动) 304 - Not Modified.(未修改)自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容是客户端有缓存情况下,服务端的一种响应,提升用户体验。 403 - Forbidden 访问被拒绝 权限不足(chmod -R 777 /data) 404 - 请求的网页不存在 500 - 大多是代码问题,或者sql报错 501 - 服务器不具备完成请求的功能 502 - Bad Gateway fpm进程挂掉或者后端程序过长时间未返回。 503 - Service Unavailable 当遇到这个状态码的时候表示服务临时不可用,比如nginx配置了频率限制,而client端又超过了配置的限制后就会收到503的响应。 504 - Gateway Time-out nginx的fastcgi模块有一个fastcgi_read_timeout配置,它表示从FastCGI server获取数据的超时时间。如果超过这个配置客户端就是收到504的响应。 ## 11、建立 TCP 连接为什么最后还要发送确认? 这主要是为了防止已失效的连接请求报文段突然又传到了 TCP 服务器,避免产生错误。 ## 12、TIME-WAIT 是什么,为什么必须等待 2MLS? 虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。 ## 13、为什么TCP建立连接握手是3次,挥手需要4次? 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。 ## 14、如果已经建立了连接,但是客户端突然出现故障了怎么办? TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。 ## 15、客户端在使用HTTPS方式与Web服务器是怎么通信的? 1. 客户端请求服务器,服务器返回数字证书(里面包括,服务器公钥,网站地址,证书颁发机构),数字证书本身使用证书私钥加密 2. 解密证书,验证证书数字签名,通过操作系统和浏览器内置的CA证书信息。验证通过后,客户端生成一个随机密码,用接收到的服务器公钥将其加密,发送到服务器 3. 用服务器私钥解密,得到随机密码 4. 握手结束,之后的通信全部使用随机密码进行对称加密通信 ## 16、WebSocket是什么? WebSocket 是一种通信协议,定义了一个全双工通信信道,仅通过 Web 上的一个 Socket 即可进行通信,主要特点 推送功能:支持由服务器向客户端推送数据的推送功能 减少通信量:只要建立起 WebSocket 连接,就希望一直保持连接状态 ## 17、什么是心跳机制? 心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制。 ## 18、HTTP 请求头部信息有哪些? 请求头部由关键字/值对组成,每行一对 1. User-Agent :客户端信息 2. Accept : 客户端希望接受的数据类型,比如 Accept:application/json 3. Connection : 表示是否需要持久连接,比如Keep-Alive 4. Host : 请求的主机名,允许多个域名同处一个IP地址,即虚拟主机 5. Cookie:浏览器端cookie ## 19、建立 TCP 连接为什么最后还要发送确认? 这主要是为了防止已失效的连接请求报文段突然又传到了 TCP 服务器,避免产生错误。 20、滑动窗口? ## 21、TCP/IP 网络拥塞怎么解决 * TCP -【拥塞控制】- 快重传、快恢复 * TCP - 拥塞控制方法 * **慢开始(slow start,慢启动)** * **拥塞避免(congestion avoidance)** * **快速重传(fast retransmit)** * **快速恢复(fast recovery)** ## 22、TCP协议可靠性是如何保证 * **序列号和确认应答信号** * **超时重发控制** * **连接管理** * **滑动窗口控制** * **流量控制** * **拥塞控制** * **序列号和确认应答信号** seq 表示当前段序列号,ack代表下一段开始位置(seq+1) * **超时重发控制** **重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔**。如果超过这个时间仍未收到确认应答,发送端将进行数据重发。 * **连接管理** 即三次握手四次挥手 * **滑动窗口控制** ![](https://img.kancloud.cn/b9/0c/b90c07409b84d2d01d197867dcded0e8_745x565.png)![](https://img.kancloud.cn/4b/b1/4bb18ca854d0343fdd54c6e425442643_792x630.png) **窗口大小就是指无需等待确认应答ACK而继续发送数据的最大值**。 这种窗口机制实现了使用了大量的缓冲区(Buffer,指的是计算机存储收发数据的的内存空间),通过对多个段同时进行确认应答的功能。 ![](https://img.kancloud.cn/4d/9b/4d9bbe7c71213563408e88910e453530_738x427.png) 对于滑动窗口有以下几点特点: * 上图中的窗口内的数据即便没有收到确认应答也可以被发送出去。不过,**在整个窗口的确认应答没有到达之前,如果其中部分数据出现丢包,那么发送端仍然要负责重传**。为此,发送端主机需要**设置缓存保留这些待被重传的数据,直到收到他们的确认应答**。 * 在滑动窗口以外的部分包括未发送的数据以及已经确认对端已收到的数据。当数据发出后若如期收到确认应答就可以不用再进行重发,此时数据就可以从缓存区清除。 * 收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置。**这样可以顺序地将多个段同时发送提高通信性能。这种机制也别称为滑动窗口控制**。 ### 拥塞控制与流量控制的区别 * **流量控制**是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止丢失数据包的。 * **拥塞控制**拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况 * **流量控制** TCP需要提供一种机制:**让发送端根据接收端实际的接收能力控制发送的数据量**。这就是所谓的流量控制。 TCP 利用**滑动窗口**实现流量控制的机制, 而滑动窗口大小是通过TCP首部的窗口大小字段来通知对方。 窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。**这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。** 不过,当接收端这个接收缓冲区面临数据溢出时,窗口大小的值就会随之设置成一个更小值,告诉发送端要控制一下发送的数据量了。 **流量控制的具体操作就是**:接收端会在确认应答发送ACK报文时,将自己的即时窗口大小rwnd(receiver window)填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值进而改变自己的发送速度。 ![](https://img.kancloud.cn/93/53/93531bb9b9753319e71af56914326aa8_632x572.jpg) **发送端停止发送数据后,什么时候可以继续发送数据呢?** 我们继续看上图,答案就是等接收端处理完了缓冲区的数据后发送一个**窗口更新**的数据包通知,发送端才可以继续根据窗口大小发送数据。 **但是如果发送端在重发超时的时间内都没有收到窗口更新的通知或者窗口更新的包丢失了,就没法正常通信了,那怎么办呢?** TCP为每一个连接设有一个**持续计时器(persistence timer)。**只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口控测数据段(这个数据段只包含一个字节),那么收到这个报文段的一方就重新设置持续计时器。 所以发送端会定时向接收端发送一个**窗口探测**的数据段,这目的是为了获取最新的窗口大小信息。 * **拥塞控制** #### 什么是拥塞 我们都知道计算机网络中的资源是有限的。某段时间内网络中对资源的需求超过了网络中的可用部分,而导致网络性能下降的情况就是拥塞。 通俗点说就是发送的数据包太多网络中的设备处理不过来,而导致网络性能下降的情况。 #### TCP 为什么要进行拥塞控制 网络中的路由器会有一个数据包处理队列,当路由器接收到的数据包太多而一下子处理不过来时,就会导致数据包处理队列过长。此时,路由器就会无条件的丢弃新接收到的数据封包。 这就会导致上层的 TCP 协议以为数据包在网络中丢失,进而重传这些数据包,而路由器又会丢弃这些重传的数据包,如此以往,就会导致网络性能急剧下降,引起网络瘫痪。因此,TCP 需要控制数据包发送的数量来避免网络性能的下降。 #### 拥塞控制原理 有了TCP的滑动窗口控制,收发主机之间即使不再以一个“段”为单位,而是以一个“窗口”为单位发送确认应答信号,所以发送主机够连续发送大量数据包。然而,**如果在通信刚开始的时候就发送大量的数据包,也有可能会导致网络的瘫痪。** 在拥塞控制中,发送方维持一个叫做**拥塞窗口cwnd**(congestion window)的状态变量。**拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化**。 发送窗口取拥塞窗口和接收端窗口的最小值,避免发送接收端窗口还大的数据。 拥塞控制使用了两个重要的算法:**慢启动算法**,**拥塞避免算法**。 **慢启动算法**: 慢启动算法的思路是,不要一开始就发送大量的数据,先试探一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。慢算法中,**每个传输轮次后将 cwnd 加倍**。慢启动,不是指拥塞窗口增长慢,而是相对于一开始就上来传输大窗口的数据要显得慢。 **拥塞避免算法**: 拥塞避免算法也是逐渐的增大 cwnd 的大小,只是采用的是**线性增长**而不是像慢启动算法那样的指数增长。 具体来说就是每个传输轮次后将 cwnd 的大小加一(加法增大),如果发现出现网络拥塞的话就按照上面的方法重新设置ssthresh的大小(乘法减小,原来的二分之一)并从cwnd=1开始重新执行慢开始算法。 ### 慢启动算法和拥塞避免算法结合: 问题:在拥塞控制中, 慢启动算法 和 拥塞避免算法 是怎么配合使用的呢? 像上面所说,慢启动算法下的cwnd大小是指数增长,所以不能任 cwnd 任意增长,所以我们引入一个慢启动门限(ssthresh)的阈值来控制 cwnd 的增长。 ssthresh的作用是: * 当cwnd < ssthresh时,使用慢开始算法。 * 当cwnd > ssthresh时,改用拥塞避免算法。 * 当cwnd = ssthresh时,慢开始与拥塞避免算法随机 还有一个问题就是这个 ssthresh 是怎么设置的呢? **TCP/IP 中规定无论是在慢开始阶段还是在拥塞避免阶段,只要发现网络中出现拥塞(没有按时收到确认),就要把ssthresh设置为此时发送窗口的一半大小**(不能小于2)。 ![](https://img.kancloud.cn/b8/c4/b8c4b372bf02d61e46f20bf5949985b3_848x449.jpg) 拥塞控制的大致流程如下: * 一开始把ssthresh初始值设置成16,开始慢启动增加拥塞窗口cwnd,直到cwnd=16 停止慢启动,开始拥塞避免算法。 * 使用拥塞避免算法线性增加cwnd,直到cwnd=24,这时候网络出现拥塞(ACK确认信号没有及时到达),把ssthresh设置成原来的一半,也就是ssthresh=12,同时把cwnd设为1。 * 重新开始慢启动,直到cwnd到达ssthresh=12,然后执行拥塞避免算法进行加法增大,直到遇到网络拥塞,把ssthresh调成原来的一一半。 * 如此反复动态计算cwnd,以达到拥塞控制的目的。 #### 快重传 VS 超时重传 TCP 的可靠传输的原理就是超时重传机制,而重发机制有两种:**超时重传机 和 快重传** * **TCP超时重传机制**,结合上面说的**慢启动**和**拥塞避免**使用就是发送完数据后开始倒计时,如果在**重发超时内**没有收到对接收方发来的ACK的话就去执行上述的**乘法减小过程(设置sstresh为原来一半)**并重新开始慢开始算法,重新发送数据。 * **TCP快重传**, 则是允许发送方再连续收到**3 个重复的确认**后就可以开始执行乘法减小过程而不必再等待重发超时时间。这就需要接收方每收到一个**失序**的报文段就立即发出重复确认以让发送方及早知道有报文段丢失,而不是等待自己发送数据的时候进行捎带确认。 ![](https://img.kancloud.cn/30/3a/303ad7221f7308b4b8b43a551086e1ce_666x443.jpg) 由于发送端不必等待每个数据段都确认才能继续发送,而是以一个窗口为单位发送数据,所以就算主机A发送的1001-2000序列号数据段丢失,主机A依然会继续发剩下的窗口大小数据,而此时主机B发现1001-2000数据丢失,它会每次收到其他序列号的数据包,都返回一个序列号1000的ACK,以此明确通知主机A,当主机A收到**三次**1000的ACK直到丢失了1001-2000数据包,就需要重传1001-2000的数据包了。 以此达到哪怕没到重发超时时间,都能快速重传的目的 #### 快恢复 **快恢复算法是与快重传算法配合使用的一个算法。** 快恢复主要是指,当快重传的时候,发送方快速收到了**3个重复的确认**,因此会认为网络不是拥塞状态,所以在**乘法减小过程(设置sstresh为原来一半)**,会启动**“拥塞避免”**,而不是TCP超时重发机制的重新启动的**慢启动** **TCP协议在实现传输可靠性上面做了很多:** * 通过**序列号和确认应答信号**确保了数据不会重复发送和重复接收。 * 同时通过**超时重发控制**保证即使数据包在传输过程中丢失,也能重发保持数据完整。 * 通过三次握手,四次挥手建立和关闭连接的**连接管理**保证了端对端的通信可靠性。 * TCP还使用了**滑动窗口控制**提高了数据传输效率 * 通过**流量控制**控制发送者的发送速度从而使接收者来得及接收,防止丢包。 * 通过**拥塞控制**就是防止过多的数据注入到网络中,避免网络中的路由器或链路不致过载,导致数据丢失。从而保证了TCP传输的可靠性。 ## 为什么选择在传输层就将数据“大卸八块”分成多个段,而不是等到网络层再分片传递给数据链路层? 因为可以提高重传的性能 需要明确的是:可靠传输是在传输层进行控制的 如果在传输层不分段,一旦出现数据丢失,整个传输层的数据都得重传 如果在传输层分了段,一旦出现数据丢失,只需要重传丢失的那些段即可 ![](https://img.kancloud.cn/02/fb/02fb2f3bcea6514ae661fb03d2eeb5a5_1351x662.png)