前端八股之计算机网络
1044
HTTP协议
1. GET和POST的请求的区别
- 应用场景:GET请求是一个幂等的请求,一般Get请求用于对服务器资源不会产生影响的场景,比如说请求一个网页的资源。而Post不是一个幂等的请求,一般用于对服务器资源会产生影响的情景,比如注册用户这一类的操作
- 是否缓存:因为两者应用场景不同,浏览器一般会对Get请求缓存,但很少对Post请求缓存。
- 发送的报文格式:Get请求的报文中实体部分为空,Post请求的报文中实体部分一般为向服务器发送的数据
- 安全性:Get请求可以将请求的参数放入url中向服务器发送,这样的做法相对于Post请求来说是不太安全的,因为请求的url会被保留在历史记录中
- 请求长度:浏览器由于对url长度的限制,所以会影响get请求发送数据时的长度。这个限制是浏览器规定的,并不是RFC规定的
- 参数类型:post的参数传递支持更多的数据类型
2. POST和PUT请求的区别
- PUT请求是向服务器端发送数据,从而修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。(可以理解为是更新数据)
- POST请求是向服务器端发送数据,该请求会改变数据的种类等资源,它会创建新的内容。(可以理解为是创建数据)
3. 常见的HTTP请求头和响应头
HTTP Request Header常见的请求头
Accept
:浏览器能够处理的内容类型Accept-Charset
:浏览器能够显示的字符集Accept-Encoding
:浏览器能够处理的压缩编码Accept-Language
:浏览器当前设置的语言Connection
:浏览器与服务器之间连接的类型Cookie
:当前页面设置的任何CookieHost
:发出请求的页面所在的域Referer
:发出请求的页面的URLUser-Agent
:浏览器的用户代理字符串
HTTP Responses Header常见的响应头
Date
:表示消息发送的时间,时间的描述格式由rfc822定义server
:服务器名称Connection
:浏览器与服务器之间连接的类型Cache-Control
:控制HTTP缓存content-type
:表示后面的文档属于什么MIME类型 常见的 Content-Type 属性值有以下四种:
application/x-www-form-urlencoded
:浏览器的原生form表单,如果不设置 enctype属性,那么最终就会以application/x-www-form-urlencoded
方式提交数据。该种方式提交的数据放在body里面,数据按照key1=val1&key2=val2
的方式进行编码,key和val都进行了URL转码。multipart/form-data
:该种方式也是一个常见的POST提交方式,通常表单上传文件时使用该种方式。application/json
:服务器消息主体是序列化后的JSON字符串。text/xml
:该种方式主要用来提交 XML 格式的数据。
4. HTTP状态码304是多好还是少好
服务器为了提高网站访问速度,对之前访问的部分页面指定缓存机制,当客户端在此对这些页面进行请求,服务器会根据缓存内容判断页面与之前是否相同,若相同便直接返回304,此时客户端调用缓存内容,不必进行二次下载。
状态码304不应该认为是一种错误,而是对客户端有缓存情况下服务端的一种响应。
搜索引擎爬虫会更加青睐内容源更新频繁的网站。通过特定时间内对网站抓取返回的状态码来调节对该网站的抓取频次。若网站在一定时间内一直处于304的状态,那么爬虫可能会降低对网站的抓取次数。相反,若网站变化的频率非常之快,每次抓取都能获取新内容,那么日积月累,的回访率也会提高。
5. 常见的HTTP请求方法
- GET: 向服务器获取数据;
- POST:将实体提交到指定的资源,通常会造成服务器资源的修改;
- PUT:上传文件,更新数据;
- DELETE:删除服务器上的对象;
- HEAD:获取报文首部,与GET相比,不返回报文主体部分;
- OPTIONS:询问支持的请求方法,用来跨域请求;
- CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信;
- TRACE: 回显服务器收到的请求,主要⽤于测试或诊断。
6. HTTP 1.0和HTTP 1.1之间有哪些区别?
- 连接方面,http1.0默认使用非持久连接,而http1.1默认使用持久连接。http1.1通过使用持久连接来使多个http请求复用同一个 TCP 连接,以此来避免使用非持久连接时每次需要建立连接的时延。
- 资源请求方面,在http1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1则在请求头引入了
range
头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。 - 缓存方面,在http1.0中主要使用header里的
If-Modified-Since
、Expires
来做为缓存判断的标准,http1.1则引入了更多的缓存控制策略,例如Etag
、If-Unmodified-Since
、If-Match
、If-None-Match
等更多可供选择的缓存头来控制缓存策略。 - http1.1中新增了host字段,用来指定服务器的域名。http1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。因此有了host字段,这样就可以将请求发往到同一台服务器上的不同网站。
- http1.1 相对于http1.0还新增了很多请求方法,如 PUT、HEAD、OPTIONS 等。
7. HTTP 1.1和HTTP 2.0的区别
- 二进制协议:HTTP/2是一个二进制协议。在HTTP/1.1版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。帧的概念是它实现多路复用的基础。
- 多路复用:HTTP/2实现了多路复用,HTTP/2仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。
- 数据流:HTTP/2使用了数据流的概念,因为HTTP/2的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流ID ,用来区分它属于哪个数据流。
- 头信息压缩:HTTP/2实现了头信息压缩,由于HTTP 1.1协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
- 服务器推送:HTTP/2允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是http2下服务器主动推送的是静态资源,和WebSocket以及使用SSE等方式向客户端发送即时数据的推送是不同的。
8. HTTP/2与HTTP/3的区别
- 传输协议:HTTP/2基于TCP协议,而HTTP/3改用QUIC协议(基于 UDP)QUIC解决了TCP的队头阻塞问题,且通过减少握手步骤(如集成TLS 1.3加密)大幅降低连接延迟
- 多路复用机制:HTTP/2的多路复用依赖二进制分帧,允许同一连接并行传输多个请求/响应,但若TCP丢包会导致所有流被阻塞。HTTP/3的QUIC协议中每个流独立处理,丢包仅影响单个流,其他流仍可正常传输
- 头部压缩算法:HTTP/2使用HPACK算法压缩头部,通过静态表和动态表减少冗余字段。HTTP/3改用QPACK,优化了流间依赖问题,支持并行流的头部压缩而不阻塞传输
- 连接建立与恢复:HTTP/2的TCP连接需三次握手 + TLS握手,延迟较高。HTTP/3的 QUIC将握手合并为一步(支持 0-RTT),且具备连接迁移能力,网络切换时无需重建连接
- 安全性:HTTP/2默认要求TLS加密,但加密与传输层分离;HTTP/3的QUIC内建加密(强制 TLS 1.3),密钥协商更高效,抗攻击能力更强
9. HTTP和HTTPS协议的区别
- HTTPS协议需要CA证书,费用较高;而HTTP协议不需要;
- HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;
- 使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
- HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全。
10. 当在浏览器中输入URL并且按下回车之后发生了什么
- 解析URL:首先会对URL进行解析,分析所需要使用的传输协议和请求的资源的路径。如果输入的URL中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查URL中是否出现了非法字符,如果存在非法字符,则对非法字符进行转义后再进行下一过程。
- 缓存判断:浏览器会判断所请求的资源是否在缓存里,如果请求的资源在缓存里并且没有失效,那么就直接使用,否则向服务器发起新的请求。
- DNS解析:下一步首先需要获取的是输入的URL中的域名的IP地址,首先会判断本地是否有该域名的IP地址的缓存,如果有则使用,如果没有则向本地DNS服务器发起请求。本地DNS服务器也会先检查是否存在缓存,如果没有就会先向根域名服务器发起请求,获得负责的顶级域名服务器的地址后,再向顶级域名服务器请求,然后获得负责的权威域名服务器的地址后,再向权威域名服务器发起请求,最终获得域名的IP地址后,本地DNS服务器再将这个IP地址返回给请求的用户。用户向本地DNS服务器发起请求属于递归请求,本地DNS服务器向各级域名服务器发起请求属于迭代请求。
- 获取MAC地址:当浏览器得到IP地址后,数据传输还需要知道目的主机MAC地址,因为应用层下发数据给传输层,TCP协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的IP地址作为目的地址。然后将下发给数据链路层,数据链路层的发送需要加入通信双方的MAC地址,本机的MAC地址作为源MAC地址,目的MAC地址需要分情况处理。通过将IP地址与本机的子网掩码相与,可以判断是否与请求主机在同一个子网里,如果在同一个子网里,可以使用ARP协议获取到目的主机的MAC地址,如果不在一个子网里,那么请求应该转发给网关,由它代为转发,此时同样可以通过ARP协议来获取网关的MAC地址,此时目的主机的MAC地址应该为网关的地址。
- TCP三次握手:下面是TCP建立连接的三次握手的过程,首先客户端向服务器发送一个SYN连接请求报文段和一个随机序号,服务端接收到请求后向服务器端发送一个SYN ACK报文段,确认连接请求,并且也向客户端发送一个随机序号。客户端接收服务器的确认应答后,进入连接建立的状态,同时向服务器也发送一个ACK确认报文段,服务器端接收到确认后,也进入连接建立状态,此时双方的连接就建立起来了。
- HTTPS握手:如果使用的是HTTPS协议,在通信前还存在TLS的一个四次握手的过程。首先由客户端向服务器端发送使用的协议的版本号、一个随机数和可以使用的加密方法。服务器端收到后,确认加密的方法,也向客户端发送一个随机数和自己的数字证书。客户端收到后,首先检查数字证书是否有效,如果有效,则再生成一个随机数,并使用证书中的公钥对随机数加密,然后发送给服务器端,并且还会提供一个前面所有内容的 hash 值供服务器端检验。服务器端接收后,使用自己的私钥对数据解密,同时向客户端发送一个前面所有内容的hash值供客户端检验。这个时候双方都有了三个随机数,按照之前所约定的加密方法,使用这三个随机数生成一把秘钥,以后双方通信前,就使用这个秘钥对数据进行加密后再传输。
- 返回数据:当页面请求发送到服务器端后,服务器端会返回一个html文件作为响应,浏览器接收到响应后,开始对html文件进行解析,开始页面的渲染过程。
- 页面渲染:浏览器首先会根据html文件构建DOM树,根据解析到的css文件构建CSSOM树,如果遇到script标签,则判端是否含有defer或者async属性,要不然script的加载和执行会造成页面的渲染的阻塞。当DOM树和CSSOM树建立好后,根据它们来构建渲染树。渲染树构建好后,会根据渲染树来进行布局。布局完成后,最后使用浏览器的UI接口对页面进行绘制。这个时候整个页面就显示出来了。
- TCP四次挥手:最后一步是TC 断开连接的四次挥手过程。若客户端认为数据发送完成,则它需要向服务端发送连接释放请求。服务端收到连接释放请求后,会告诉应用层要释放TCP链接。然后会发送ACK包,并进入CLOSE_WAIT状态,此时表明客户端到服务端的连接已经释放,不再接收客户端发的数据了。但是因为TCP连接是双向的,所以服务端仍旧可以发送数据给客户端。服务端如果此时还有没发完的数据会继续发送,完毕后会向客户端发送连接释放请求,然后服务端便进入LAST-ACK状态。客户端收到释放请求后,向服务端发送确认应答,此时客户端进入TIME-WAIT状态。该状态会持续2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃)时间,若该时间段内没有服务端的重发请求的话,就进入CLOSED状态。当服务端收到确认应答后,也便进入CLOSED状态。
11. HTTP请求报文的是什么样的?
请求报⽂有4部分组成:
- 请求⾏
- 请求头部
- 空⾏
- 请求体
其中:
- 请求⾏包括:请求⽅法字段、URL字段、HTTP协议版本字段。它们⽤空格分隔。例如,GET /index.html HTTP/1.1。
- 请求头部:请求头部由关键字/值对组成,每⾏⼀对,关键字和值⽤英⽂冒号“:”分隔
- 请求体: post put等请求携带的数据
HTTP状态码
类别 | 原因 | 描述 |
---|---|---|
1xx | Informational(信息性状态码) | 接受的请求正在处理 |
2xx | Success(成功状态码) | 请求正常处理完毕 |
3xx | Redirection(重定向状态码) | 需要进行附加操作一完成请求 |
4xx | Client Error (客户端错误状态码) | 服务器无法处理请求 |
5xx | Server Error(服务器错误状态码) | 服务器处理请求出错 |
1. 2XX (Success 成功状态码)
200 OK
200 OK表示客户端发来的请求被服务器端正常处理了。
204 No Content
该状态码表示客户端发送的请求已经在服务器端正常处理了,但是没有返回的内容,响应报文中不包含实体的主体部分。一般在只需要从客户端往服务器端发送信息,而服务器端不需要往客户端发送内容时使用。
206 Partial Content
该状态码表示客户端进行了范围请求,而服务器端执行了这部分的GET请求。响应报文中包含由Content-Range指定范围的实体内容。
2. 3XX (Redirection 重定向状态码)
301 Moved Permanently
该状态码表示请求的资源已经被分配了新的URI,以后应使用资源指定的URI。新的UR 会在 HTTP 响应头中的Location首部字段指定。若用户已经把原来的URI保存为书签,此时会按照Location中新的URI重新保存该书签。同时,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址。
使用场景:
- 当我们想换个域名,旧的域名不再使用时,用户访问旧域名时用301就重定向到新的域名。其实也是告诉搜索引擎收录的域名需要对新的域名进行收录。
- 在搜索引擎的搜索结果中出现了不带www的域名,而带www的域名却没有收录,这个时候可以用301重定向来告诉搜索引擎我们目标的域名是哪一个。
302 Found
该状态码表示请求的资源被分配到了新的URI,希望用户(本次)能使用新的URI访问资源。和301 Moved Permanently状态码相似,但是302代表的资源不是被永久重定向,只是临时性质的。也就是说已移动的资源对应的URI将来还有可能发生改变。
使用场景:
- 当我们在做活动时,登录到首页自动重定向,进入活动页面。
- 未登陆的用户访问用户中心重定向到登录页面。
- 访问404页面重新定向到首页。
303 See Other
该状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源。
303 状态码和302 Found状态码有着相似的功能,但是303状态码明确表示客户端应当采用GET方法获取资源。
304 Not Modified
状态码304并不是一种错误,而是告诉客户端有缓存,直接使用缓存中的数据。返回页面的只有头部信息,是没有内容部分的,这样在一定程度上提高了网页的性能。
3. 4XX (Client Error 客户端错误状态码)
400 Bad Request
该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。
401 Unauthorized
该状态码表示发送的请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息。若之前已进行过一次请求,则表示用户认证失败
403 Forbidden
该状态码表明请求资源的访问被服务器拒绝了,服务器端没有必要给出详细理由,但是可以在响应报文实体的主体中进行说明。进入该状态后,不能再继续进行验证。该访问是永久禁止的,并且与应用逻辑密切相关。
404 Not Found
该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。
405 Method Not Allowed
该状态码表示客户端请求的方法虽然能被服务器识别,但是服务器禁止使用该方法。客户端可以通过 OPTIONS 方法(预检)来查看服务器允许的访问方法
4. 5XX (Server Error 服务器错误状态码)
500 Internal Server Error
该状态码表明服务器端在执行请求时发生了错误。也有可能是Web应用存在的bug或某些临时的故障。
502 Bad Gateway
该状态码表明扮演网关或代理角色的服务器,从上游服务器中接收到的响应是无效的。
503 Service Unavailable
该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
使用场景:
- 服务器停机维护时,主动用503响应请求;
- nginx 设置限速,超过限速,会返回503。
504 Gateway Timeout
该状态码表示网关或者代理的服务器无法在规定的时间内获得想要的响应。他是HTTP 1.1中新加入的。
网络模型
1. OSI七层模型
1. 应用层
OSI参考模型中最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,POP3、SMTP等。
2. 表示层
表示层提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。
在项目开发中,为了方便数据传输,可以使 base64对数据进行编解码。如果按功能来划分,base64应该是工作在表示层。
3. 会话层
会话层就是负责建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。
4. 传输层
传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。通常说的,TCP UDP就是在这一层。端口号既是这里的“端”。
5. 网络层
本层通过 IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。IP协议是 Internet的基础。可以这样理解,网络层规定了数据包的传输路线,而传输层则规定了数据包的传输方式。
6. 数据链路层
将比特组合成字节,再将字节组合成帧,使用链路层地址 (以太网使用MAC地址)来访问介质,并进行差错检测。
网络层与数据链路层的对比,通过上面的描述,我们或许可以这样理解,网络层是规划了数据包的传输路线,而数据链路层就是传输路线。不过,在数据链路层上还增加了差错控制的功能。
7. 物理层
际最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。
2. TCP/IP五层协议
其实就是把OSI七层模型中的应用层、表示层、会话层合并为应用层。
TCP与UDP
1. TCP和UDP的概念及特点
UDP
UDP的全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。
它的特点如下:
- 面向无连接: 首先UDP是不需要和TCP一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。
- 有单播,多播,广播的功能: UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式
- 面向报文: 发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。
- 不可靠性: 首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包
- 头部开销小,传输数据报文时是很高效的
TCP
TCP的全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP是面向连接的、可靠的流协议
它的特点如下:
- 面向连接: 面向连接,是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”,这样能建立可靠的连接。
- 仅支持单播传输: 每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式
- 面向字节流: TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输
- 可靠传输: 对于可靠传输,判断丢包、误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
- 提供拥塞控制: 当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。
- 提供全双工通信: TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。
2. TCP和UDP的使用场景
- TCP应用场景:效率要求相对低,但对准确性要求相对高的场景。因为传输中需要对数据确认、重发、排序等操作,相比之下效率没有UDP高。例如:文件传输(准确高要求高、但是速度可以相对慢)、接受邮件、远程登录。
- UDP应用场景:效率要求相对高,对准确性要求相对低的场景。例如:QQ聊天、在线视频、网络语音电话(即时通讯,速度要求高,但是出现偶尔断续不是太大问题,并且此处完全不可以使用重发机制)、广播通信(广播、多播)。
3. TCP的重传机制
由于TCP的下层网络(网络层)可能出现丢失、重复或失序的情况,TCP协议提供可靠数据传输服务。为保证数据传输的正确性,TCP会重传其认为已丢失(包括报文中的比特错误)的包。TCP使用两套独立的机制来完成重传,一是基于时间,二是基于确认信息。
TCP在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。
4. TCP的拥塞控制机制
慢启动
- 在开始发送的时候设置cwnd = 1(cwnd指的是拥塞窗口)
- 思路:开始的时候不要发送大量数据,而是先测试一下网络的拥塞程度,由小到大增加拥塞窗口的大小。每次cwnd翻倍。
- 为了防止cwnd增长过大引起网络拥塞,设置一个慢启动门限(ssthresh 状态变量)
- 当cnwd < ssthresh,使用慢启动算法
- 当cnwd = ssthresh,既可使用慢启动算法,也可以使用拥塞避免算法
- 当cnwd > ssthresh,使用拥塞避免算法
拥塞避免
- 拥塞避免未必能够完全避免拥塞,是说在拥塞避免阶段将拥塞窗口控制为按线性增长,使网络不容易出现阻塞。
- 思路: 让拥塞窗口cwnd缓慢的增大,即每经过一个返回时间RTT就把发送方的拥塞控制窗口加一
- 无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现超时,就把慢开始门限设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为1,执行慢开始算法。
快速恢复
- 当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半。但是接下去并不执行慢开始算法。
- 考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。
5. TCP的流量控制机制
一般来说,流量控制就是为了让发送方发送数据的速度不要太快,要让接收方来得及接收。TCP采用大小可变的滑动窗口进行流量控制,窗口大小的单位是字节。这里说的窗口大小其实就是每次传输的数据大小。
- 当一个连接建立时,连接的每一端分配一个缓冲区来保存输入的数据,并将缓冲区的大小发送给另一端。
- 当数据到达时,接收方发送确认,其中包含了自己剩余的缓冲区大小。
- 如果接收方应用程序读数据的速度能够与数据到达的速度一样快,接收方将在每一确认中发送一个正的窗口通告。
- 如果发送方操作的速度快于接收方,接收到的数据最终将充满接收方的缓冲区,导致接收方通告一个零窗口 。发送方收到一个零窗口通告时,必须停止发送,直到接收方重新通告一个正的窗口。
6. TCP的三次握手和四次挥手
三次握手
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。
刚开始客户端处于Closed的状态,服务端处于Listen状态。
- 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN
首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
- 第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN。同时会把客户端的 ISN + 1 作为ACK 的值
在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y
- 第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文
确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
那为什么要三次握手呢?两次不行吗?
为了确认双方的接收能力和发送能力都正常
四次挥手
刚开始双方都处于ESTABLISHED状态,假如是客户端先发起关闭请求。四次挥手的过程如下
- 第一次挥手: 客户端会发送一个 FIN 报文,报文中会指定一个序列号。
即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
- 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值
即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。
- 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。
即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。
- 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值
即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
那为什么需要四次挥手呢?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,故需要四次挥手。
7. TCP粘包是怎么回事,如何处理?
默认情况下, TCP 连接会启⽤延迟传送算法 (Nagle 算法), 在数据发送之前缓存他们。如果短时间有多个数据发送, 会缓冲到⼀起作⼀次发送, 这样可以减少 IO 消耗提⾼性能。
下面看⼀个例⼦, 连续调⽤两次send分别发送两段数据data1和data2, 在接收端有以下⼏种常⻅的情况:
A. 先接收到data1, 然后接收到 data2
B. 先接收到data1的部分数据, 然后接收到data1余下的部分以及 ata2的全部
C. 先接收到了data 的全部数据和data2的部分数据, 然后接收到了data2的余下的数据
D. ⼀次性接收到了data1和data2的全部数据
其中的 BCD 就是我们常⻅的粘包的情况. ⽽对于处理粘包的问题, 常⻅的解决⽅案有:
- 多次发送之前间隔⼀个等待时间:只需要等上⼀段时间再进⾏下⼀次 send 就好, 适⽤于交互频率特别低的场景
- 关闭Nagle算法:该⽅法⽐较适⽤于每次发送的数据都⽐较⼤ (但不是⽂件那么⼤), 并且频率不是特别⾼的场景
- 进⾏封包/拆包:封包/拆包是⽬前业内常⻅的解决⽅案了。即给每个数据包在发送之前, 于其前/后放⼀些有特征的数据, 然后收到数据的时 候根据特征数据分割出来各个数据包。
WebSocket
1. 对 WebSocket 的理解
WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。
WebSocket 的出现就解决了半双工通信的弊端。它最大的特点是:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。
WebSocket原理:客户端向 WebSocket 服务器通知(notify)一个带有所有接收者ID(recipients IDs)的事件(event),服务器接收后立即通知所有活跃的(active)客户端,只有ID在接收者ID序列中的客户端才会处理这个事件。
2. 即时通讯的实现:短轮询、长轮询、SSE和WebSocket间的区别?
- 短轮询的基本思路:浏览器每隔一段时间向浏览器发送http请求,服务器端在收到请求后,不论是否有数据更新,都直接进行响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。这种方式的优点是比较简单,易于理解。缺点是这种方式由于需要不断的建立http连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。
- 长轮询的基本思路:首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。长轮询和短轮询比起来,它的优点是明显减少了很多不必要的http请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。
- SSE的基本思想:服务器使用流信息向服务器推送信息。严格地说,http协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。SSE就是利用这种机制,使用流信息向浏览器推送信息。它基于http协议,目前除了 IE/Edge,其他浏览器都支持。它相对于前面两种方式来说,不需要建立过多的http请求,相比之下节约了资源。
- WebSocket是HTML5定义的一个新协议议,与传统的http协议不同,该协议允许由服务器主动的向客户端推送信息。使用WebSocket协议的缺点是在服务器端的配置比较复杂WebSocket是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息,而SSE的方式是单向通信的,只能由服务器端向客户端推送信息,如果客户端需要发送信息就是属于下一个http请求了。
上面的四个通信协议,前三个都是基于HTTP协议的。
对于这四种即使通信协议,从性能的角度来看:
WebSocket > 长连接(SEE) > 长轮询 > 短轮询
但是,我们如果考虑浏览器的兼容性问题,顺序就恰恰相反了:
短轮询 > 长轮询 > 长连接(SEE) > WebSocket
所以,还是要根据具体的使用场景来判断使用哪种方式。