关于HTTP网络通信相关
HTTP
HTTP 全称超⽂文本传输协议,是建立在tcp传输层协议上的
网络模型
七层网络
http协议位于应用层
URL
统一资源
协议部分
协议部分为http还是https,会用//为分隔符
域名部分
在发送请求前,会向DNS服务器解析IP,如果已经知道ip,还可以跳过DNS解析那一步,直接把IP当做域名部分使用
端口
域名后面有些时候会带有端口,和域名之间用:分隔,端口不是一个URL的必须的部分。当网址为http://时,默认端口为80
当网址为https://时,默认端口为443,以上两种都可以省略端口号。上面的URL其实省略了443端口号
虚拟目录
域名的第一个/开始到最后一个/为止,是虚拟目录的部分
文件名
域名最后一个/开始到?为止,是文件名部分, 没有?, #就到结束
url和uri的区别
url: 统一资源定位符
uri: 统一资源标识符
URL是URI的子集
请求方法
get
请求指定的页面信息,并返回消息主体(body)+头信息(header),会有长度限制,过长容易截断,并不安全,请求参数在url里
head
HEAD和GET本质是一样的,区别在于HEAD只返回头信息(header),不返回消息主体(body)
如果想要判断某个资源是否存在,虽然用GET也能做到,但这里用HEAD还省下拿body的消耗,返回状态码200就是有404就是无
如果请求的是一个比较大的资源,比如一个超大视频和文件,你只想知道它到底有多大,而不需要整个下载下来,这时候使用HEAD请求,返回的headers会带有文件的大小(content-lenght)
post
向服务器提交数据,请求参数在data里,加密的,不会被截断
put
推送添加,类似post,不过一般用post代替
delete
删除一个资源,一般用post代替
patch
用于对资源进行部分修改
connect
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
trace
回显服务器收到的请求,主要用于测试或诊断
options
它用于获取当前URL所支持的方法。若请求成功,则它会在HTTP响应头部中带上给各种“Allow”的头,表明某个请求在对应的服务器中都支持哪种请求方法
指明了允许携带的首部字段
允许什么方法
允许跨域请求的域名,允许所有*
允许携带的header信息
结果缓存时间多久
什么时候options请求
在跨域(记住这个词,待会解释)的情况下,浏览器发起复杂请求前会自动发起 options 请求
浏览器必须首先使用 options 方法发起一个预检请求,从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求
简单请求与复杂请求
某些请求不会触发 CORS 预检请求,这样的请求一般称为”简单请求”,而会触发预检的请求则为”复杂请求”,get,head, post
跨域
同源是指,域名、协议、端口均相同
而非同源之间网页调用就是我们所说的跨域
options问题
复杂请求的条件其实非常容易满足,而一旦满足复杂请求的条件,则浏览器便会发送2次请求(一次预检options,一次复杂请求),这一次options就一来一回(一个RTT),显然会导致延迟和不必要的网络资源浪费,高并发情况下则可能为服务器带来严重的性能消耗
优化options请求
每次复杂请求前都会调用一次options,这其实非常没有必要。因为大部分时候相同的请求,短时间内获得的结果是不会变的
通过缓存优化
Access-Control-Max-Age就是优化这个流程中使用的一个Header。它的作用是当你每次请求options方法时,服务端返回调用支持的方法(Access-Control-Allow-Methods )和Headers(Access-Control-Allow-Headers)有哪些,同时告诉你,它在接下来 Access-Control-Max-Age时间(单位是秒)里都支持,则这段时间内,不再需要使用options进行请求。特别注意的是,当Access-Control-Max-Age的值为-1时,表示禁用缓存,每一次请求都需要发送预检请求,即用OPTIONS请求进行检测
状态码
1xx:表示请求已接收,继续处理
2xx: 表示请求已成功,接受
3xx:重定向
4xx:客户端错误
5xx:服务端错误
常见状态码
200 : 代表请求已成功,数据也正常返回
204:常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据
206: 服务器已经成功处理了部分GET请求。类似于B站看视频或者迅雷这类的HTTP下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载
301:表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问
302:表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问 Loocation字段
304:表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制
307: 内部重定向,跳转到别的网址上
400:请求报文有错
403:禁止访问
404:没有这个地址路由,或者方法不对,get,post
499:由于服务端处理时间过长,客户端超时。一般常见于,后端服务器处理时间过长,而客户端也设置了一个超时等待时间,客户端等得“不耐烦”了,主动关掉连接时报出
501:请求的功能不支持
502: 服务器崩溃
503:表示服务器当前很忙,暂时无法响应服务器,类似“网络服务正忙,请稍后重试”的意思
504:网络请求过程中,由于服务端处理时间过长,网关超时。一般常见于,后端服务器逻辑处理时间过长,甚至长于nginx设置的最长等待时间时报错。它跟 499 状态码非常像,区别在于499表示的是客户端超时,504是网关超时。如果是499超时,可以考虑修改客户端的代码调整超时时间,如果是504,则考虑调整nginx的超时配置。
headers
content-length
Content-Length是HTTP的消息长度,用十进制数字表示。Content-Length首部指出报文中消息的当前实际字节大小。如果消息文本进行了gzip压缩的话, Content-Length指的就是压缩后的大小而不是原始大小
正常情况下Content-Length是不需要手动去设置的,大部分语言的网络库都会自动封装好,但是如果在一些特殊情况下,出现Content-Length与实际要发送的消息大小不一致,就会出现一些问题
小于实际长度:会被截断
大于实际长度:会阻塞
range
请求文件的起始结束阶段,视频播放等
不支持range,200,会下载整个文件
服务器支持 Range Requests,会读取视频文件,响应码为 206,则浏览器会在接收到足够字节(比如当前播放进度往后推20s)时结束掉请求,以节省网络流量;当播放进度继续往前,缓存不够时,浏览器会发起一个新的 Range Requests 请求,请求的 Range 直接从缓存结尾的字节开始,只加载剩余的部分文件。同时返回的Response Headers中有一个 content-range 的字段域,用于告诉了客户端发送了多少数据。content-range描述了响应覆盖的范围和整个实体长度。一般格式:Content-Range:开始字节位置-结束字节位置/文件大小(byte)
connection
短链接close
长连接keep-alive,表示链接不关闭,做到只建立一次连接,多次资源请求都复用该连接,完成后关闭
Request Header和Reponse Header中都有可能出现一个Connection: keep-alive 头信息。Request Header里的Connection: keep-alive 头是为了告诉服务端,客户端想要以长连接形式进行通信。而Response Header里的Connection: keep-alive 头是服务端告诉客户端,我的服务器支持以长连接的方式进行通信。如果不能使用长连接,会返回 Connection: close
tcp层连接,需要三次握手,四次挥手,每次都需要这个步骤,如果能只连接一次,保持住这个连接不断开,期间通信就可以省下建立连接和断开连接的过程,对于提升HTTP性能有很大的帮助
长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接。但是在长连接的应用场景下,需要有一方主动关闭连接。如果客户端和服务端之间的连接一直不关闭的话,连接数则会越来越多,严重的时候会造成资源占用过高。
解决方案也比较简单。如果这些连接其实长时间内并没有任何数据传输的话,那其实属于空闲连接,这时候可以在服务端设置空闲连接的存活时间,超过一定时间后由服务端主动断掉,从而保证无用连接及时释放
cookies
识别用户身份,持久化用户信息,保存到本地
Referrer Policy 和 Referrer
Referrer 是HTTP请求header的报文头,用于指明当前流量的来源参考页面,常被用于分析用户来源等信息。通过这个信息,我们可以知道访客是怎么来到当前页面的
而 Referrer Policy 则是用于控制Referrer信息传不传、传哪些信息、在什么时候传的策略,过滤referrer的敏感信息
缓存策略
cache-control: private
具有“private”指令的响应只能由客户端缓存,不能由中间代理(例如 CDN或代理)缓存。这些资源通常是包含私密数据的资源,例如显示用户个人信息的网站。
cache-control: public
相反,“public”指令表示资源可以由任何缓存存储。
cache-control: no-store
带有“no-store”指令的响应无法缓存到任何位置,也永不缓存。也就是说,用户每次请求此数据时,都必须将请求发送到源站服务器以获取新副本。此指令通常保留给包含极其敏感数据的资源,例如银行帐户信息。
cache-control: max-age
此指令指定了生存时间,也就是资源在下载后可以缓存多少秒钟。例如,如果将最大期限设置为 1800,则首次从服务器请求资源后的 1800 秒(30 分钟)内,后续请求都会向用户提供该资源的缓存版本。如果 30 分钟后用户再次请求资源,则客户端需要向服务器重新请求该资源。
cache-control: no-cache
从B站截图里可以看出,使用的缓存控制指令是cache-control: no-cache。它表示,只有先检查资源没有更新版本后,才可使用所请求资源的缓存版本。那么问题来了,怎么判断资源是否有更新版本呢?这就需要 ETag
ETAG
Etag是 Entity tag的缩写,是服务端的一个资源版本的令牌标识。在 HTTP 响应头中将其传送到客户端。每当资源更新时,此令牌会更新。
比如,浏览器第一次请求资源的时候,服务端返回了这个资源的ETag: “095933fff2323351d3b495f2f879616f1762f752”。
当浏览器再次请求这个资源的时候,浏览器会将If-None-Match: “095933fff2323351d3b495f2f879616f1762f752” 传输给服务端,服务端拿到该ETAG,对比资源是否发生变化。
如果资源未发生改变,则返回304HTTP状态码,不返回具体的资源。
否则表示资源已经更新,浏览器需要下载新版本以提供给用户。
此过程可确保用户始终获得资源的最新版本,并且无需进行不必要的下载
TCP与UDP
TCP/IP协议是一个协议簇。里面包括很多协议的,UDP只是其中的一个
udp
无连接:只知道对端的IP和端口号就可以发送,不需要实现建立连接。
不可靠:没有确认机制, 没有重传机制。如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息。
面向数据报: 应用层交给UDP多长的报文, UDP原样发送既不会拆分,也不会合并。如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom,接收100个字节,而不能循环调用10次recvfrom,每次接收10个字节。所以UDP不能够灵活的控制读写数据的次数和数量
udp缓冲区
接收缓冲区:具有接收缓冲区,但不能保证收到的UDP报文的顺序和发送UDP报的顺序一致,如果缓冲区满了再到达的UDP数据报就会被丢弃
发送缓冲区:没有发送缓冲区,调用sendto时会直接将数据交给内核,由内核将数据传给网络层协议进行后续的传输动作
不保证可靠性,它没有重传机制,当报文丢失时,UDP不需要重新发送,而TCP不同,他必须具备发送缓冲区,当报文丢失时,TCP必须保证重新发送,用户不会管,所以必须要具备发送缓冲区
长度大小
UDP协议首部中有一个16位的大长度. 也就是说一个UDP能传输的报文长度是64K(包含UDP首部)。如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装
DNS域名解析就是udp协议
TFTP:简单文件传输协议
tcp
三次握手,四次挥手
一个TCP连接通常分为三个阶段:启动、数据传输、退出(关闭)
ACK —— 确认,使得确认号有效。
RST —— 重置连接(经常看到的reset by peer)就是此字段
SYN —— 用于初如化一个连接的序列号
FIN —— 该报文段的发送方已经结束向对方发送数据
建立连接阶段(三次握手)
1、客户端发送一个SYN段,并指明客户端的初始序列号,即ISN(c)
2、服务端发送自己的SYN段作为应答,同样指明自己的ISN(s)。为了确认客户端的SYN,将ISN(c)+1作为ACK数值。这样,每发送一个SYN,序列号就会加1. 如果有丢失的情况,则会重传
3、为了确认服务器端的SYN,客户端将ISN(s)+1作为返回的ACK数值,并携带客户到服务端的数据
第三次握手可以携带数据,前两次不可以
断开连接(四次挥手)
1、客户端发送一个FIN段,并包含一个希望接收者看到的自己当前的序列号K. 同时还包含一个ACK表示确认对方最近一次发过来的数据
2、服务端将K值加1作为ACK序号值,表明收到了上一个包。这时上层的应用程序会被告知另一端发起了关闭操作,通常这将引起应用程序发起自己的关闭操作
3、服务端发起自己的FIN段,ACK=K+1
4、客户端确认。ACK=L+1
为啥要3,4
“3次握手”的作用就是双方都能明确自己和对方的收、发能力是正常的
第一次:客户端发送网络包,服务端收到
服务端知道客户端的发送能力、服务端的接收能力是正常的
第二次:服务端发包,客户端收到
客户端知道服务端的接收、发送能力,客户端的接收、发送能力是正常的
第三次:客户端发包,服务端收到
客户端的接收、发送能力,服务端的发送、接收能力是正常的
得需要客户端服务端都知道对方以及自己的收发能力正常,所以需要3次,2次不足以满足
首要原因:
1、防止旧的重复连接初始化造成混乱
一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
那么此时服务端就会回一个 SYN + ACK 报文给客户端;
客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接
如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接:
如果是历史连接(序列号过期或超时),则第三次握手发送的报文是 RST 报文,以此中止历史连接;
如果不是历史连接,则第三次发送的报文是 ACK 报文,通信双方就会成功建立连接;
所以要3次
2、有效同步序列号,没有ack的话就无法确认序列号是否同步
接收方可以去除重复的数据;
接收方可以根据数据包的序列号按序接收;
可以标识发送出去的数据包中, 哪些是已经被对方收到的
3、资源浪费,没有ack的话,网络阻塞,就会多出很多冗余链接
4次挥手
TCP连接是双向传输的对等的模式,就是说双方都可以同时向对方发送或接收数据,一方要关闭,对方会回一个ACK,此时一个方向的连接关闭。但是另一个方向仍然可以继续传输数据,等到发送完了所有的数据后,会发送一个FIN段来关闭此方向上的连接。接收方发送ACK确认关闭连接
服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接
接收到FIN报文的一方只能回复一个ACK, 它是无法马上返回对方一个FIN报文段的,因为结束数据传输的“指令”是上层应用层给出的
为啥建立是3,断开是4
收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送
如果服务器已经没有数据需要传了,第二次第三次可以合并作一次
syn flood攻击
恶意的向某个服务器端口发送大量的SYN包,则可以使服务器打开大量的半开连接,分配TCB(Transmission Control Block), 从而消耗大量的服务器资源,同时也使得正常的连接请求无法被相应。当开放了一个TCP端口后,该端口就处于Listening状态,不停地监视发到该端口的Syn报文,一 旦接收到Client发来的Syn报文,就需要为该请求分配一个TCB,通常一个TCB至少需要280个字节,在某些操作系统中TCB甚至需要1300个字节,并返回一个SYN ACK命令,立即转为SYN-RECEIVED即半开连接状态。系统会为此耗尽资源
解决方法:
监控无效链接,半开连接,不活动连接,达到阈值,拆除
延缓TCB分配: 服务器收到SYN包的时候,使用 数据结构 TCB 来存储这次连接的信息,成功建立连接之后才分配TCB
超时重传机制
TCP在传输数据过程中,还加入了超时重传机制。假设主机A发送数据给主机B,主机B没有收到数据包,主机B自然就不会应答,如果主机A在一个特定时间间隔内没有收到主机B发来的确认应答,就会进行重发,这就是超时重传机制
有可能会收到很多重复数据,那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的包丢弃掉,这时候我们可以利用tcp报文里的16位 序列号,数据校验,就可以很容易做到去重的效果
linux的超时重传是500ms的整数倍
RTT 包的往返时间
RTO 超时重传时间
当超时时间 RTO 较大时,重发就慢,丢了老半天才重发,没有效率,性能差;
当超时时间 RTO 较小时,会导致可能并没有丢就重发,于是重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发
超时重传时间 RTO 的值应该略大于报文往返 RTT 的值
快速重传
当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
快速重传机制只解决了一个问题,就是超时时间的问题,但是它依然面临着另外一个问题。就是重传的时候,是重传之前的一个,还是重传所有的问题
SACK和D-SACK
SACK:可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据
D-SACK:其主要使用了 SACK 来告诉「发送方」有哪些数据被重复接收了
Time Wait状态
服务器运行起来然后将服务器关闭掉,再次重新启动服务器会发现一个问题:就是不能马上再次绑定这个端口号和ip,需要等一会才可以重新绑定,其实等的这一会就是TIME_WAIT状态
协议规定主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL的时间后才能回到CLOSED状态
TIME_WAIT是为了防止最后一个ACK丢失,如果没有TIME_WAIT,那么主动断开连接的一方就已经关闭连接,但是另一方还没有断开连接,它收不到确认ACK会认为自己上次发送的FIN报文丢失会重发该报文,但是另一方已经断开连接了,这就会造成连接不一致的问题,所以TIME_WAIT是必须的
MSL是TCP报文在发送缓冲区的最大生存时间,如果TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失
但是当用户量请求很大的时候,主动断开连接,就会产生大量的timewait状态
优化:
1、使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socket描述符
2、net.ipv4.tcp_tw_reuse 和 tcp_timestamps,复用处于timewait状态的新连接
net.ipv4.tcp_tw_reuse要慎用,因为使用了它就必然要打开时间戳的支持 net.ipv4.tcp_timestamps,当客户端与服务端主机时间不同步时,客户端的发送的消息会被直接拒绝掉
3、net.ipv4.tcp_max_tw_buckets一旦超过这个值时,系统就会将所有的 TIME_WAIT 连接状态重置,暴力解决
close wait状态
客户端是主动断开连接的一方,在服务器端假设没有关闭新连接,这时服务器端就会产生一个CLOSE_WAIT状态
服务器上出现大量的CLOSE_WAIT状态,原因就是服务器没有正确的关闭 socket,导致四次挥手没有正确完成
滑动窗口
一次一次发送性能较低,每一次都要ack确认,一次发送多条,窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,收到第一个ACK后滑动窗口向后移动,继续发送后面的数据,
内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答。只有确认应答过的数据,才能从缓冲区删掉,窗口越大,则网络的吞吐率就越高
累计确认,累计应答, ack600丢失,ack700收到,则认为600收到
三个指针控制窗口大小,窗口大小,已发送未确认收到,未发送,可发送范围
服务端繁忙会减少窗口大小,先减少缓存,再减少窗口会引发丢包现象
TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间在减少缓存,这样就可以避免了丢包情况
非0窗口的ack丢失引发死锁
窗口关闭引发死锁:为了解决这个问题,TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。
如果持续计时器超时,就会发送窗口探测 ( Window probe ) 报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小
丢包与快重传
数据到达,ack丢失:发送后面的数据1001-2000字节的数据,收到2001的ack,就可以认为前面的1000的数据接收成功
数据丢失: 1001-2000丢失,后面的数据接收到之后,接收方会收到失序的报文,则会发送1001的ack连续3次,发送端连续3次收到1001的ack就会将1001-2000的数据重发,同时后面的数据接收不变
流量控制
接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被装满,这个时候如果发送端继续发送,就会造成丢包
TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制
1、接收端将自己可以接收的缓冲区大小放入TCP首部中的”窗口大小”字段,通过ACK确认报文通知发送端
2、窗口大小字段越大,说明网络的吞吐量越高,接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端
3、发送端接受到这个窗口之后,就会减慢自己的发送速度,如果接收端缓冲区满了,就会将窗口置为0。这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端,防止窗口更新丢失,发送端会有窗口探测包
拥塞控制
拥塞窗口是发送方维护,滑动窗口是接收方维护,发送窗口的值是swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值
只要网络中没有出现拥塞,cwnd 就会增大;
但网络中出现了拥塞,cwnd 就减少
发生超时重传就认为是拥塞
慢启动
在刚开始网络拥堵时再发送大量数据仍然有可能会造成堵塞
所以tcp有慢启动机制,开始发送的数据量较少,试探网络情况,然后指数级增长,增长很快
为了不增长的那么快,因此不能使拥塞窗口单纯的加倍,此处引入一个叫做慢启动的阈值当拥塞窗口超过这个阈值的时候,不再按照指数方式增长, 而是按照线性方式增长
少量的丢包,我们仅仅是触发超时重传。大量的丢包,我们就认为网络拥塞。当TCP通信开始后,网络吞吐量会逐渐上升。随着网络发生拥堵,吞吐量会立刻下降。拥塞控制归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案
拥塞避免
慢启动增长转为线性增长
就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。
当触发了重传机制,也就进入了「拥塞发生算法」
拥塞发生
超时重传的话就会重新慢启动,减少数据流,比较暴力,会造成网络卡顿,慢启动门限会变成1
快速重传:比较平缓,拥塞窗口变为原来一半,慢启动门限也会变为拥塞窗口大小,然后进入快速恢复
快速恢复:持续再增长拥塞窗口
延迟应答
如果接收方立刻返回ack,这时候返回的窗口可能比较小。假设接收端缓冲区为1M 一次收到了500K的数据。如果立刻应答,返回的窗口就是500K。 但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了,在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些也能处理过来。如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M。
窗口越大,网络吞吐量就越大,传输效率就越高。我们的目标是在保证网络不拥塞的情况下尽量提高传输效率。
数量限制: 每隔N个包就应答一次
时间限制: 超过大延迟时间就应答一次
PS:具体的数量和超时时间, 依操作系统不同也有差异; 一般N取2, 超时时间取200ms
相关问题
tcp与udp的特点与区别及应用场景
基于连接vs无连接
TCP是面向连接的协议。
UDP是无连接的协议。UDP更加适合消息的多播发布,从单个点向多个点传输消息。可靠性
TCP提供交付保证,传输过程中丢失,将会重发。
UDP是不可靠的,不提供任何交付保证。(网游和视频的丢包情况)有序性
TCP保证了消息的有序性,即使到达客户端顺序不同,TCP也会排序。
UDP不提供有序性保证。数据边界
TCP不保存数据边界。
虽然TCP也将在收集所有字节之后生成一个完整的消息,但是这些信息在传给传输给接受端之前将储存在TCP缓冲区,以确保更好的使用网络带宽。
UDP保证。
在UDP中,数据包单独发送的,只有当他们到达时,才会再次集成。包有明确的界限来哪些包已经收到,这意味着在消息发送后,在接收器接口将会有一个读操作,来生成一个完整的消息。
速度
TCP速度慢
UDP速度快。应用在在线视频媒体,电视广播和多人在线游戏。发送消耗
TCP是重量级。
UDP是轻量级。
因为UDP传输的信息中不承担任何间接创造连接,保证交货或秩序的的信息。
这也反映在用于报头大小。
- 报头大小
TCP头大。
一个TCP数据包报头的大小是20字节。
TCP报头中包含序列号,ACK号,数据偏移量,保留,控制位,窗口,紧急指针,可选项,填充项,校验位,源端口和目的端口。
UDP头小。
UDP数据报报头是8个字节。
而UDP报头只包含长度,源端口号,目的端口,和校验和。
- 拥塞或流控制
TCP有流量控制。
在任何用户数据可以被发送之前,TCP需要三数据包来设置一个套接字连接。TCP处理的可靠性和拥塞控制。
UDP不能进行流量控制。
- 应用
由于TCP提供可靠交付和有序性的保证,它是最适合需要高可靠并且对传输时间要求不高的应用。
UDP是更适合的应用程序需要快速,高效的传输的应用,如游戏。
UDP是无状态的性质,在服务器端需要对大量客户端产生的少量请求进行应答的应用中是非常有用的。
在实践中,TCP被用于金融领域,如FIX协议是一种基于TCP的协议,而UDP是大量使用在游戏和娱乐场所。
10.上层使用的协议
基于TCP协议的:Telnet,FTP以及SMTP协议。
基于UDP协议的:DHCP、DNS、SNMP、TFTP、BOOTP。
udp与tcp的首部位
UDP 首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的
tcp首部字段:序号,确认号,控制位(ack, fin,syn),窗口值
为什么3,4
相关看上面
time wait状态
相关看上面
短链接和长连接
Client 向 Server 发送消息,Server 回应 Client,然后一次读写就完成了,这时候双方任何一个都可以发起 close 操作,不过一般都是 Client 先发起 close 操作。短连接一般只会在 Client/Server 间传递一次读写操作。
短连接的优点:管理起来比较简单,建立存在的连接都是有用的连接,不需要额外的控制手段
Client 与 Server 完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。
关闭策略:Client 与 Server 之间的连接如果一直不关闭的话,随着客户端连接越来越多,Server 压力也越来越大,这时候 Server 端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致 Server 端服务受损;如果条件再允许可以以客户端为颗粒度,限制每个客户端的最大长连接数,从而避免某个客户端连累后端的服务
地址栏输入 URL 发生了什么,http工作原理
1、在浏览器地址栏中输入url,先解析url,检测url地址是否合法
2、查看本地缓存,是否有缓存
3、浏览器会根据你输入的 URL 地址,去查找域名是否被本地 DNS 缓存,不同浏览器对 DNS 的设置不同,如果浏览器缓存了你想访问的 URL 地址,那就直接返回 ip。如果没有缓存你的 URL 地址,浏览器就会发起系统调用来查询本机 hosts 文件是否有配置 ip 地址,如果找到,直接返回。如果找不到,就向网络中发起一个 DNS 查询
4、查询到ip之后放到协议栈,浏览器需要和目标服务器建立 TCP 连接,需要经过三次握手的过程,然后由IP模块,封装网络包,生成包头,ip报文
5、IP报文加上MAC头部,由网卡转换电信号发送,有交换机,路由,发送到服务端,服务端解析报文,TCP头部, IP头部,MAC头部,
5、在建立连接后,浏览器会向目标服务器发起 HTTP-GET 请求,包括其中的 URL,HTTP 1.1 后默认使用长连接,只需要一次握手即可多次传输数据。
6、如果目标服务器只是一个简单的页面,就会直接返回。但是对于某些大型网站的站点,往往不会直接返回主机名所在的页面,而会直接重定向。返回的状态码就不是 200 ,而是 301,302 以 3 开头的重定向码,浏览器在获取了重定向响应后,在响应报文中 Location 项找到重定向地址,浏览器重新第一步访问即可。
7、然后浏览器重新发送请求,携带新的 URL,返回状态码 200 OK,表示服务器可以响应请求,返回报文
https工作原理
在进行通信前,首先会进行 HTTP 的三次握手,握手完成后,再进行 TLS 的握手过程
TLS 旨在为 Internet 提供通信安全的加密协议。TLS 握手是启动和使用 TLS 加密的通信会话的过程
为什么post是两个tcp包
post先去检测一下服务器是否能正常应答,然后再把data携带过去,如果应答不了,就没有了第二步数据传输
get与post请求的区别
1、get 请求的 URL 有长度限制,而 post 请求会把参数和值放在消息体中,对数据长度没有要求。
2、get 请求会被浏览器主动 cache,而 post 不会,除非手动设置。
3、get 请求在浏览器反复的 回退/前进 操作是无害的,而 post 操作会再次提交表单请求。
4、get 请求在发送过程中会产生一个 TCP 数据包;post 在发送过程中会产生两个 TCP 数据包。对于 get 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据);而对于 post,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)
5、get 方法是不安全的,因为你在发送请求的过程中,你的请求参数会拼在 URL 后面, post 方法是把参数放在请求体 body 中的,这对用户来说不可见
无状态协议
无状态协议(Stateless Protocol) 就是指浏览器对于事务的处理没有记忆能力
HTTP 就是一种无状态的协议,他对用户的操作没有记忆能力
通过cookie实现(大概20个,30个,50个左右, cookie大小限制4000kb左右)
cookies与session的区别
http与https的区别
HTTPS=SSL+HTTP
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
(这个只是默认端口不一样,实际上端口是可以改的)
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
put与post的区别
PUT 和POST方法的区别是,PUT方法是幂等的:连续调用一次或者多次的效果相同(无副作用),而POST方法是非幂等的
put和patcch
PUT和PATCH都是更新资源,而PATCH用来对已知资源进行局部更新
http/2特点,优势
头部压缩
HTTP2中:
同域名下所有通信都在单个连接上完成。
单个连接可以承载任意数量的双向数据流。
数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装
二进制格式数据传输
分层
五层: 应用(http, DNS),传输(tcp,udp),网络(ip),链路(mac), 物理
七层:加上表示层和会话层
tcp全连接队列与半连接队列溢出
全连接队列溢出:
当服务端并发处理大量请求时,如果 TCP 全连接队列过小,就容易溢出。发生 TCP 全连接队溢出的时候,后续的请求就会被丢弃,这样就会出现服务端请求数量上不去的现象
查看溢出:netstat -s |grep overflowed
调整全连接队列最大值
ss -lnt 查看全连接队列
Recv-Q:当前全连接队列的大小,也就是当前已完成三次握手并等待服务端 accept() 的 TCP 连接个数;
Send-Q:当前全连接最大队列长度,上面的输出结果说明监听 8088 端口的 TCP 服务进程,最大全连接长度为 128;
TCP 全连接队列足最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)
somaxconn 是 Linux 内核的参数,默认值是 128,可以通过 /proc/sys/net/core/somaxconn 来设置其值;
backlog 是 listen(int sockfd, int backlog) 函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度
半连接队列溢出:
服务端处于 SYN_RECV 状态的 TCP 连接,就是在 TCP 半连接队列
netstat -natp |grep syn_recv |wc -l
查看溢出:netstat -s |grep “SYNs to Listen”
隔几秒执行几次,如果有上升的趋势,说明当前存在半连接队列溢出的现象
如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃
半连接最大队列一般是256个
syncookies功能:不使用半连接队列,服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK
0:关闭,1:半连接对列放不下开启, 2:无条件开启
防御syn攻击:
服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的 SYN 接收队列(未连接队列)
增大半连接队列:也需要同同时增大全连接队列
开启syncookies
减少重传次数:当服务端受到 SYN 攻击时,就会有大量处于 SYN_REVC 状态的 TCP 连接,处于这个状态的 TCP 会重传 SYN+ACK ,当重传超过次数达到上限后,就会断开连接,加快连接断开
ping的工作原理
ping 是基于 ICMP 协议工作的,互联网控制报文协议
确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等
1、Ping 命令会构建一个 固定格式的 ICMP 请求数据包(Echo Request)
2、ICMP协议会将数据包,连同去往的地址放到IP层
3、IP协议将本机作为源地址,目的地址,加上一些控制信息,交给链路层
4、链路层加上mac地址,到物理层发出
5、服务端收到后拆包,检测目的地址,然后给icmp协议处理,然后响应
如果已经建立链接,客户端突然出现故障。怎么办
保活机制
定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序
net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9