网络知识
1. 请详细介绍下TCP的三次握手机制,为什么要三次握手? 四次挥手, 为什么要四次挥手,挥手后为什么要保持2MSL?
1.1 为什么要有握手?
1.2 为什么是三次?
1.3 为什么要四次?
1.4 为什么包保持2MSL?
2. 简单介绍下HTTP协议中缓存的处理流程?
2.1 缓存的应用流程是什么?
2.2 与缓存相关的HTTP头部有哪些?
3. 在地址栏键入URL后,网络世界发生么什么?
4. 使用HTTP长连接有哪些优点?
5. CLOSE_WAIT状态产生的原因?
6. 介绍下多播是怎样实现的?
7. 服务器的最大并发连接数是多少?
8. TCP和UDP协议该如何选择?
9. TLS/SSL协议是如何保障信息安全的?
10. HTTP2协议有哪些优点?
请详细介绍下TCP的三次握手机制,为什么要三次握手? 四次挥手, 为什么要四次挥手,挥手后为什么要保持2MSL?
三次握手
首先介绍一下三次握手,客户端发起连接请求(SYN=1,seq=客户随机序列),服务端收到请求并回复(SYN=1, seq=服务随机序列,ACK=1 seq=seq(客户随机序列)+1),客户端收到相应并回复(ACK=1, seq=seq(服务随机序列)+1),三次握手完成。
为什么是三次不是二次,因为二次握手只能确认客户端能收到服务端请求,但是服务端不能确认客户端是否收到请求。同时二次握手无法解决重复连接问题,当握手中网络拥塞,导致客户端重新发了一个新的握手请求,过了一会客户端收到旧握手请求,客户端就可以向客户端发送一个RST ,连接中止。一会时间后,新握手抵达,正常建立连接
因为TCP是可靠性连接,通过三次握手可以有效的避免重复连接,确认双方是否连接,同时节约资源。
四次挥手
客户端发起断开连接请求 FIN=1 seq=seq+1,服务端收到请求回复ACK=1 seq=seq+1, 服务端处理完请求后回复FIN=1, seq=seq+1,客户端收到请求回复ACK=1, seq=seq+1 等待2MSL后连接关闭。
为什么要等待2MSL, 因为1MSL为一次报文在网络存活的时间,过了这个时间报文会被丢弃(linux中默认2MSL为60秒)。 如果客户端少于2MSL关闭,网络拥塞,导致服务端没有收到请求, 重新发送FIN, 而客户端已经关闭,这时会导致双方无法正常关闭。假如此时客户端新请求使用同个端口连接服务端,而服务端没有正常关闭,会带来数据混淆。大于2MSL浪费资源。
1.为了保证连接的可靠关闭。如果server没有收到最后一个ACK,那么就会重发FIN。
2.为了避免端口重用带来的数据混淆。如果client直接进入CLOSED状态,又用相同端口号向server建立一个连接,上一次连接的部分数据在网络中延迟到达server,数据就可能发生混淆了。
为什么seq要随机?
这样是为了网络安全,如果不是随机产生初始序列号,黑客将会以很容易的方式获取到你与其他主机之间的初始化序列号,并且伪造序列号进行攻击
为什么seq+1?
确认收到的序列,并且告诉发送端下一次发送的序列号从哪里开始(便于接收方对数据排序,便于选择重传)
什么是SYN洪范泛攻击?
- SYN Flood利用TCP协议缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发来海量的请求连接的第一个握手包(SYN包),被攻击服务器回应第二个握手包(SYN+ACK包),因为对方是假冒IP,对方永远收不到包且不会回应第三个握手包。导致被攻击服务器保持大量SYN_RECV状态的“半连接”,并且会重试默认5次回应第二个握手包,大量随机的恶意syn占满了未完成连接队列,导致正常合法的syn排不上队列,让正常的业务请求连接不进来。【服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击】
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击【在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击】
怎么解决?
-
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术:
- 当服务器接受到 SYN 报文段时,不直接为该 TCP 分配资源,而只是打开一个半开的套接字。接着会使用 SYN 报文段的源 Id,目的 Id,端口号以及只有服务器自己知道的一个秘密函数生成一个 cookie,并把 cookie 作为序列号响应给客户端。
- 如果客户端是正常建立连接,将会返回一个确认字段为 cookie + 1 的报文段。接下来服务器会根据确认报文的源 Id,目的 Id,端口号以及秘密函数计算出一个结果,如果结果的值 + 1 等于确认字段的值,则证明是刚刚请求连接的客户端,这时候才为该 TCP 分配
Q:TCP三次握手中,最后一次回复丢失,会发生什么?
- 如果最后一次ACK在网络中丢失,那么Server端(服务端)该TCP连接的状态仍为SYN_RECV,并且根据 TCP的超时重传机制依次等待3秒、6秒、12秒后重新发送 SYN+ACK 包,以便 Client(客户端)重新发送ACK包
- 如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server(服务端)自动关闭这个连接
- 但是Client(客户端)认为这个连接已经建立,如果Client(客户端)端向Server(服务端)发送数据,Server端(服务端)将以RST包(Reset,标示复位,用于异常的关闭连接)响应,此时,客户端知道第三次握手失败
TCP四次挥手
- 主动断开方(客户端/服务端)-发送一个 FIN,用来关闭主动断开方(客户端/服务端)到被动断开方(客户端/服务端)的数据传送
- 被动断开方(客户端/服务端)-收到这个 FIN,它发回一 个 ACK,确认序号为收到的序号加1 。和 SYN 一样,一个 FIN 将占用一个序号
- 被动点开方(客户端/服务端)-关闭与主动断开方(客户端/服务端)的连接,发送一个FIN给主动断开方(客户端/服务端)
- 主动断开方(客户端/服务端)-发回 ACK 报文确认,并将确认序号设置为收到序号加1
Q:为什么连接的时候是三次握手,关闭的时候却是四次握手?
- 建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
- 关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以服务器可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接。因此,服务器ACK和FIN一般都会分开发送,从而导致多了一次。
Q:为什么TCP挥手每两次中间有一个 FIN-WAIT2等待时间?
- 主动关闭的一端调用完close以后(即发FIN给被动关闭的一端, 并且收到其对FIN的确认ACK)则进入FIN_WAIT_2状态。如果这个时候因为网络突然断掉、被动关闭的一段宕机等原因,导致主动关闭的一端不能收到被动关闭的一端发来的FIN(防止对端不发送关闭连接的FIN包给本端),这个时候就需要FIN_WAIT_2定时器, 如果在该定时器超时的时候,还是没收到被动关闭一端发来的FIN,那么直接释放这个链接,进入CLOSE状态
Q:为什么客户端最后还要等待2MSL?为什么还有个TIME-WAIT的时间等待?
- 保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,服务器已经发送了FIN+ACK报文,请求断开,客户端却没有回应,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
- 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,这样新的连接中不会出现旧连接的请求报文。
- 2MSL,最大报文生存时间,一个MSL 30 秒,2MSL = 60s
Q:客户端 TIME-WAIT 状态过多会产生什么后果?怎样处理?
- 作为服务器,短时间内关闭了大量的Client连接,就会造成服务器上出现大量的TIME_WAIT连接,占据大量的tuple /tApl/ ,严重消耗着服务器的资源,此时部分客户端就会显示连接不上
- 作为客户端,短时间内大量的短连接,会大量消耗的Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法在发起新的连接了
-
在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上
-
- 高并发可以让服务器在短时间范围内同时占用大量端口,而端口有个0~65535的范围,并不是很多,刨除系统和其他服务要用的,剩下的就更少了
- 短连接表示“业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间”的连接
-
解决方法:
-
- 用负载均衡来抗这些高并发的短请求;
- 服务器可以设置 SO_REUSEADDR 套接字选项来避免 TIME_WAIT状态,TIME_WAIT 状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的
- 强制关闭,发送 RST 包越过TIMEWAIT状态,直接进入CLOSED状态
Q:服务器出现了大量 CLOSE_WAIT 状态如何解决?
- 大量 CLOSE_WAIT 表示程序出现了问题,对方的 socket 已经关闭连接,而我方忙于读或写没有及时关闭连接,需要检查代码,特别是释放资源的代码,或者是处理请求的线程配置。
Q:服务端会有一个TIME_WAIT状态吗?如果是服务端主动断开连接呢?
-
发起链接的主动方基本都是客户端,但是断开连接的主动方服务器和客户端都可以充当,也就是说,只要是主动断开连接的,就会有 TIME_WAIT状态
-
四次挥手是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发
-
由于TCP连接时全双工的,因此,每个方向的数据传输通道都必须要单独进行关闭。
简单介绍下HTTP协议中缓存的处理流程?
Expires、Cache-control、缓存时间、Etag、Last-Modified
Expires:
版本:HTTP1.0
作用:指定缓存的到期时间,时间为从服务器返回的绝对时间
缺点:返回的缓存时间是服务器的绝对时间,跟本地的时间有误差,更改本地时间会对缓存的处理产生影响
Cache-Control:
版本:HTTP1.1
作用:用来取代Expires,有多个属性,可以很好的控制浏览器缓存
no-cache:不启用缓存
max-age:用户请求时,会生成一个缓存的副本,副本过期的期限由关键字的相对时间来决定
only-if-cached:告知服务器,仅能返回缓存的响应,没有缓存就返回504
max-state:请求不到数据、展现缓存上的数据,max-state就是定义一个可以超出期限时间使用缓存的时间段。
public:所有都缓存
private:对单个用户或部分响应信息,不能被共享缓存处理
Last-Modified:
作用:服务器将资源传递给客户端时,会将资源最后更改的时间以"Last-Modified:GMT"的形式加在实体首部上一起返回给客户端,下次请求是,会把改信息附带在请求报文中一并带给服务器去做检查,如果值和服务器上最终修改时间一致,则说明该资源没有被更改,直接返回304状态码
ETag:
作用:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则有服务器决定)。
在地址栏键入URL后,网络世界发生么什么?
先域名解析 在浏览器上查询对应DNS缓存,没有到本机,没有到hosts文件, 没有到路由,没有再到网络服务商, 没有根DNS服务器 返回ip, 通过ip请求建立连接TCP(HTTPS/HTTP) 三次握手 到服务器获取数据 返回四次挥手 浏览器渲染
使用HTTP长连接有哪些优点?
http1.0默认是短连接。也就是说,客户端和服务器每进行一次HTTP操作就会建立一次连接,任务结束就会中断连接。导致一个页面可能要请求很多次连接。浪费资源
http1.1支持长连接 在相应头加入connection:keep-alive ,建立连接之后其他请求也可能通过这个连接。 可以省去较多的新建TCP和关闭的操作,省时。比较适合请求资源频繁的客户。一般客户端不会主动关闭连接,如果连接一直不关闭的话,会存在一个问题,随着用户端连接越来越多,server会扛不住。这时候服务端需要一些额外策略来关闭这些连接。限制每个客户端的最大连接数
5. CLOSE_WAIT状态产生的原因?
如果我们的服务器程序处于CLOSE_WAIT状态的话,说明套接字是被动关闭的!
6. 介绍下多播是怎样实现的?
解答思路:先解释什么是多播,介绍使用多播有什么好处
TCP单播
单播,转发一百次 都是用一个主机进行的复制100次
UDP 广播、多播
但是,多播一般是由网络设备交换机和路由器来做这个事情,可以提升发送端的性能
7. 服务器的最大并发连接数是多少?
解答思路:先解释并发连接是受什么来决定的?在回答具体的最大并发连接数,以及如何扩大该连接数(延伸方面可以再回答怎么实现高并发以及LInux下的高并发优化)
首先,问题中描述的65535(2的16次方)个连接指的是客户端连接数的限制,而你作为服务器,别人来连你,理论上是没有限制的。注意,仅仅理论上。
65535是怎么来的?
是TCP协议规定的端口字段的最大范围,2个字节,16比特,每一比特有0和1 2种状态,按照排列组合,2的16次方,一共就是65536,端口0预留不用,就是65535。
8. TCP和UDP协议该如何选择?
解答思路:两者对比分别分析其优点,再根据实际情况进行选择。
TCP 与 UDP 的区别:TCP是面向连接的,可靠的字节流服务;
UDP是面向无连接的,不可靠的数据报服务。
UDP:一对多、高效、简单、实时性好、无队头阻塞问题
TCP:传递任意长度消息、可靠、流量控制、拥塞控制
常见的 TCP应用有:FTP、SSH、Telnet、SMTP、HTTP;
常见的UDP应用有:流媒体、实时游戏、直播、物联网、QQ 文件传输、QQ语音、QQ视频等
9. TLS/SSL协议是如何保障信息安全的?
解答思路:解释PKI证书体系、密钥交换协议、对称加密算法
加密分为“对称加密”和“非对称加密”两种:
对称加密:所谓的“对称加密”,意思就是说:“加密”和“解密”使用相同的密钥。
非对称加密::所谓的“非对称加密”,意思就是说:“加密”和“解密”使用不同的密钥。
10. HTTP2协议有哪些优点?
首先HTTP2是在HTTP1.x版本上的改良。
1、多路复用。HTTP1.x版本长连接不支持多路复用,是一次请求-响应,建立一个连接,用完关闭,每一个请求都要建立一个连接,在2.0可以多个请求可同时在一个连接上并行执行;
2、二进制分帧。1.x解析基于文本,在2.0中基于二进制,解析错误少,更高效;
3、服务端推送。此外在2.0之后支持服务端推送(一种在客户端请求之前发送数据的机制,服务器可以对客户端的一个请求发送多个响应。服务端推送让 HTTP1.x 时代使用内嵌资源的优化手段变得没有意义);
4、首部压缩。HTTP/1.1并不支持 HTTP 首部压缩,在 HTTP/2 使用了专门为首部压缩而设计的 HPACK 算法。
5、Stream优先级。在HTTP2.0中Stream可以根据依赖关系和权重设置优先级。先级高的stream会被server优先处理和返回给客户端,stream还可以依赖其它的sub streams。
11. TCP报文首部有哪些字段,说说其作用
- 16位端口号:源端口号,主机该报文段是来自哪里;目标端口号,要传给哪个上层协议或应用程序
- 32位序号:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。
- 32位确认号:用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1。
- 4位头部长度:表示tcp头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。
- 6位标志位:URG(紧急指针是否有效),ACK(表示确认号是否有效),PSH(缓冲区尚未填满),RST(表示要求对方重新建立连接),SYN(建立连接消息标志接),FIN(表示告知对方本端要关闭连接了)
- 16位窗口大小:是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
- 16位校验和:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。
- 16位紧急指针:一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法
12. TCP是如何保证可靠性的
- TCP的连接是基于三次握手,而断开则是四次挥手。确保连接和断开的可靠性。
- TCP的可靠性,还体现在有状态;TCP会记录哪些数据发送了,哪些数据被接受了,哪些没有被接受,并且保证数据包按序到达,保证数据传输不出差错。
- TCP的可靠性,还体现在可控制。它有报文校验、ACK应答、超时重传(发送方)、失序数据重传(接收方)、丢弃重复数据、流量控制(滑动窗口)和拥塞控制等机制。
13 . TCP重传机制
超时重传
TCP 为了实现可靠传输,实现了重传机制。最基本的重传机制,就是超时重传,即在发送数据报文时,设定一个定时器,每间隔一段时间,没有收到对方的ACK确认应答报文,就会重发该报文。
这个间隔时间,一般设置为多少呢?我们先来看下什么叫RTT(Round-Trip Time,往返时间)。
RTT就是,一个数据包从发出去到回来的时间,即数据包的一次往返时间。超时重传时间,就是Retransmission Timeout ,简称RTO。
RTO设置多久呢?
- 如果RTO比较小,那很可能数据都没有丢失,就重发了,这会导致网络阻塞,会导致更多的超时出现。
- 如果RTO比较大,等到花儿都谢了还是没有重发,那效果就不好了。
一般情况下,RTO略大于RTT,效果是最好的。一些小伙伴会问,超时时间有没有计算公式呢?有的!有个标准方法算RTO的公式,也叫Jacobson / Karels 算法。我们一起来看下计算RTO的公式
1. 先计算SRTT(计算平滑的RTT)
SRTT = (1 - α) * SRTT + α * RTT //求 SRTT 的加权平均
2. 再计算RTTVAR (round-trip time variation)
RTTVAR = (1 - β) * RTTVAR + β * (|RTT - SRTT|) //计算 SRTT 与真实值的差距
3. 最终的RTO
RTO = µ * SRTT + ∂ * RTTVAR = SRTT + 4·RTTVAR
其中,α = 0.125,β = 0.25, μ = 1,∂ = 4
,这些参数都是大量结果得出的最优参数。
但是,超时重传会有这些缺点:
★
- 当一个报文段丢失时,会等待一定的超时周期然后才重传分组,增加了端到端的时延。
- 当一个报文段丢失时,在其等待超时的过程中,可能会出现这种情况:其后的报文段已经被接收端接收但却迟迟得不到确认,发送端会认为也丢失了,从而引起不必要的重传,既浪费资源也浪费时间。
”
并且,TCP有个策略,就是超时时间间隔会加倍。超时重传需要等待很长时间。因此,还可以使用快速重传机制。
快速重传
快速重传机制,它不以时间驱动,而是以数据驱动。它基于接收端的反馈信息来引发重传。
一起来看下快速重传流程:
快速重传流程
发送端发送了 1,2,3,4,5,6 份数据:
- 第一份 Seq=1 先送到了,于是就 Ack 回 2;
- 第二份 Seq=2 也送到了,假设也正常,于是ACK 回 3;
- 第三份 Seq=3 由于网络等其他原因,没送到;
- 第四份 Seq=4 也送到了,但是因为Seq3没收到。所以ACK回3;
- 后面的 Seq=4,5的也送到了,但是ACK还是回复3,因为Seq=3没收到。
- 发送端连着收到三个重复冗余ACK=3的确认(实际上是4个,但是前面一个是正常的ACK,后面三个才是重复冗余的),便知道哪个报文段在传输过程中丢失了,于是在定时器过期之前,重传该报文段。
- 最后,接收到收到了 Seq3,此时因为 Seq=4,5,6都收到了,于是ACK回7.
但快速重传还可能会有个问题:ACK只向发送端告知最大的有序报文段,到底是哪个报文丢失了呢?并不确定!那到底该重传多少个包呢?
★
是重传 Seq3 呢?还是重传 Seq3、Seq4、Seq5、Seq6 呢?因为发送端并不清楚这三个连续的 ACK3 是谁传回来的。
”
带选择确认的重传(SACK)
为了解决快速重传的问题:应该重传多少个包? TCP提供了SACK方法(带选择确认的重传,Selective Acknowledgment)。
SACK机制就是,在快速重传的基础上,接收端返回最近收到的报文段的序列号范围,这样发送端就知道接收端哪些数据包没收到,酱紫就很清楚该重传哪些数据包啦。SACK标记是加在TCP头部选项字段里面的。
SACK机制
如上图中,发送端收到了三次同样的ACK=30的确认报文,于是就会触发快速重发机制,通过SACK信息发现只有30~39
这段数据丢失,于是重发时就只选择了这个30~39
的TCP报文段进行重发。
D-SACK
D-SACK,即Duplicate SACK(重复SACK),在SACK的基础上做了一些扩展,,主要用来告诉发送方,有哪些数据包自己重复接受了。DSACK的目的是帮助发送方判断,是否发生了包失序、ACK丢失、包重复或伪重传。让TCP可以更好的做网络流控。来看个图吧:
14. TCP滑动窗口
TCP 发送一个数据,需要收到确认应答,才会发送下一个数据。这样有个缺点,就是效率会比较低。
★
这就好像我们面对面聊天,你说完一句,我应答后,你才会说下一句。那么,如果我在忙其他事情,没有能够及时回复你。你说完一句后,要等到我忙完回复你,你才说下句,这显然很不现实。
”
为了解决这个问题,TCP引入了窗口,它是操作系统开辟的一个缓存空间。窗口大小值表示无需等待确认应答,而可以继续发送数据的最大值。
TCP头部有个字段叫win,也即那个16位的窗口大小,它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,从而达到流量控制的目的。
★
通俗点讲,就是接受方每次收到数据包,在发送确认报文的时候,同时告诉发送方,自己的缓存区还有多少空余空间,缓冲区的空余空间,我们就称之为接受窗口大小。这就是win。
”
TCP 滑动窗口分为两种: 发送窗口和接收窗口。发送端的滑动窗口包含四大部分,如下:
- 已发送且已收到ACK确认
- 已发送但未收到ACK确认
- 未发送但可以发送
- 未发送也不可以发送
- 虚线矩形框,就是发送窗口。
- SND.WND: 表示发送窗口的大小,上图虚线框的格子数就是14个。
- SND.UNA: 一个绝对指针,它指向的是已发送但未确认的第一个字节的序列号。
- SND.NXT:下一个发送的位置,它指向未发送但可以发送的第一个字节的序列号。
接收方的滑动窗口包含三大部分,如下:
- 已成功接收并确认
- 未收到数据但可以接收
- 未收到数据并不可以接收的数据
- 虚线矩形框,就是接收窗口。
- REV.WND: 表示接收窗口的大小,上图虚线框的格子就是9个。
- REV.NXT:下一个接收的位置,它指向未收到但可以接收的第一个字节的序列号。
15. TCP流量控制
TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是流量控制。
首先双方三次握手,初始化各自的窗口大小,均为 400 个字节。
TCP的流量控制图
16.TCP拥塞控制
拥塞控制是作用于网络的,防止过多的数据包注入到网络中,避免出现网络负载过大的情况。它的目标主要是最大化利用网络上瓶颈链路的带宽。它跟流量控制又有什么区别呢?流量控制是作用于接收者的,根据接收端的实际接收能力控制发送速度,防止分组丢失的。
★
只要网络中没有出现拥塞,拥塞窗口的值就可以再增大一些,以便把更多的数据包发送出去,但只要网络出现拥塞,拥塞窗口的值就应该减小一些,以减少注入到网络中的数据包数。
实际上,拥塞控制主要有这几种常用算法
- 慢启动
- 拥塞避免
- 拥塞发生
- 快速恢复
慢启动算法
慢启动算法,表面意思就是,别急慢慢来。它表示TCP建立连接完成后,一开始不要发送大量的数据,而是先探测一下网络的拥塞程度。由小到大逐渐增加拥塞窗口的大小,如果没有出现丢包,每收到一个ACK,就将拥塞窗口cwnd大小就加1(单位是MSS)。每轮次发送窗口增加一倍,呈指数增长,如果出现丢包,拥塞窗口就减半,进入拥塞避免阶段。
- TCP连接完成,初始化cwnd = 1,表明可以传一个MSS单位大小的数据。
- 每当收到一个ACK,cwnd就加一;
- 每当过了一个RTT,cwnd就增加一倍; 呈指数让升
为了防止cwnd增长过大引起网络拥塞,还需设置一个慢启动阀值ssthresh(slow start threshold)状态变量。当cwnd
到达该阀值后,就好像水管被关小了水龙头一样,减少拥塞状态。即当cwnd >ssthresh时,进入了拥塞避免算法。
拥塞避免算法
一般来说,慢启动阀值ssthresh是65535字节,cwnd
到达慢启动阀值后
- 每收到一个ACK时,cwnd = cwnd + 1/cwnd
- 当每过一个RTT时,cwnd = cwnd + 1
显然这是一个线性上升的算法,避免过快导致网络拥塞问题。
拥塞发生
当网络拥塞发生丢包时,会有两种情况:
- RTO超时重传
- 快速重传
如果是发生了RTO超时重传,就会使用拥塞发生算法
- 慢启动阀值sshthresh = cwnd /2
- cwnd 重置为 1
- 进入新的慢启动过程
这真的是辛辛苦苦几十年,一朝回到解放前。其实还有更好的处理方式,就是快速重传。发送方收到3个连续重复的ACK时,就会快速地重传,不必等待RTO超时再重传。
image.png
慢启动阀值ssthresh 和 cwnd 变化如下:
- 拥塞窗口大小 cwnd = cwnd/2
- 慢启动阀值 ssthresh = cwnd
- 进入快速恢复算法
快速恢复
快速重传和快速恢复算法一般同时使用。快速恢复算法认为,还有3个重复ACK收到,说明网络也没那么糟糕,所以没有必要像RTO超时那么强烈。
正如前面所说,进入快速恢复之前,cwnd 和 sshthresh已被更新:
- cwnd = cwnd /2
- sshthresh = cwnd
然后,真正的快速算法如下:
- cwnd = sshthresh + 3
- 重传重复的那几个ACK(即丢失的那几个数据包)
- 如果再收到重复的 ACK,那么 cwnd = cwnd +1
- 如果收到新数据的 ACK 后, cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入了拥塞避免的算法了。
17. 半连接队列和 SYN Flood 攻击的关系
TCP进入三次握手前,服务端会从CLOSED状态变为LISTEN状态,同时在内部创建了两个队列:半连接队列(SYN队列)和全连接队列(ACCEPT队列)。
什么是半连接队列(SYN队列) 呢? 什么是全连接队列(ACCEPT队列) 呢?回忆下TCP三次握手的图:
三次握手
- TCP三次握手时,客户端发送SYN到服务端,服务端收到之后,便回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN队列,即半连接队列。
- 当客户端回复ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入ACCEPT队列,即全连接队列。
SYN Flood是一种典型的DoS (Denial of Service,拒绝服务) 攻击,它在短时间内,伪造不存在的IP地址,向服务器大量发起SYN报文。当服务器回复SYN+ACK报文后,不会收到ACK回应报文,导致服务器上建立大量的半连接半连接队列满了,这就无法处理正常的TCP请求啦。
主要有 syn cookie和SYN Proxy防火墙等方案应对。
- syn cookie:在收到SYN包后,服务器根据一定的方法,以数据包的源地址、端口等信息为参数计算出一个cookie值作为自己的SYNACK包的序列号,回复SYN+ACK后,服务器并不立即分配资源进行处理,等收到发送方的ACK包后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包。
- SYN Proxy防火墙:服务器防火墙会对收到的每一个SYN报文进行代理和回应,并保持半连接。等发送方将ACK包返回后,再重新构造SYN包发到服务器,建立真正的TCP连接。
18 Nagle算法和延迟确认
Nagle算法
如果发送端疯狂地向接收端发送很小的包,比如就1个字节,那么亲爱的小伙伴,你们觉得会有什么问题呢?
★
TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。
”
Nagle算法的基本定义是:任意时刻,最多只能有一个未被确认的小段。所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。
Nagle算法的实现规则:
- 如果包长度达到MSS,则允许发送;
- 如果该包含有FIN,则允许发送;
- 设置了TCP_NODELAY选项,则允许发送;
- 未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
- 上述条件都未满足,但发生了超时(一般为200ms),则立即发送。
延迟确认
如果接受方刚接收到发送方的数据包,在很短很短的时间内,又接收到第二个包。那么请问接收方是一个一个地回复好点,还是合并一起回复好呢?
★
接收方收到数据包后,如果暂时没有数据要发给对端,它可以等一段时再确认(Linux上默认是40ms)。如果这段时间刚好有数据要传给对端,ACK就随着数据传输,而不需要单独发送一次ACK。如果超过时间还没有数据要发送,也发送ACK,避免对端以为丢包。
”
但是有些场景不能延迟确认,比如发现了乱序包、接收到了大于一个 frame 的报文,且需要调整窗口大小等。
一般情况下,Nagle算法和延迟确认不能一起使用,Nagle算法意味着延迟发,延迟确认意味着延迟接收,酱紫就会造成更大的延迟,会产生性能问题。
19. TCP粘包和拆包
TCP是面向流,没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。
TCP的粘包和拆包
为什么会产生粘包和拆包呢?
- 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;
- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;
- 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包;
- 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。
解决方案:
- 发送端将每个数据包封装为固定长度
- 在数据尾部增加特殊字符进行分割
- 将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小。
select和epoll的区别?
select
1)每次调用select,都需要把fd集合(文件描述集合)从用户态拷贝到内核态,这个开销在fd很多时会很大
2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
epoll
epoll通过在Linux内核中申请一个简易的文件系统(文件系统一般用什么数据结构实现?红黑树)。把原先的select/poll调用分成了3个部分:
1)调用epoll_create( ), 创建红黑树和就绪链表。
2)调用epoll_ctl() ,如果增加请求socket, 先检查红黑树中是否存在,存在直接返回,不存在则添加到红黑树上,然后向内核注册回调函数,用于当中断事件来临时向就绪链表中插入socket。
3)调用epoll_wait(), 调用epoll_wait时,返回就绪链表的数据。
epoll触发方式水平触发LT和边缘触发ET:
EPOLLIN事件(可读)
内核中的socket接收缓冲区为空 低电平
内核中的socket接收缓冲区不为空 高电平
EPOLLOUT事件(可写)
内核中的socke发送缓冲区不满 高电平
内核中的socke发送缓冲区满 低电平
LT是水平触发,也就是高电平就会触发
ET是边沿触发,低电平->高电平或者高电平->低电平触发
水平触发
LT模式下,只要一个句柄上的事件 没有处理完,重新将这个句柄放到就绪链表中,调用epoll_wait时会返回这个句柄
边缘触发
ET模式下,只要一个句柄上的事件 没有处理完,仅在第一次返回 。除非新中断到。
1.对于读操作,如果read没有一次读完buff数据,下一次将得不到就绪通知(ET特性),造成buff中数据无法读出,除非有新数据到达。
解决方法:将套接字设置为非阻塞,用while循环包住read,只要buff中有数据,就一直读。一直读到产生EAGIN错误。若ET模式下使用阻塞IO,则程序一定会阻塞在最后一次write或read操作,因此说ET模式下一定要使用非阻塞IO。
2.对于写操作主要因为ET模式下非阻塞需要我们考虑如何将用户要求写的数据写完。
解决方法:只要buff还有空间且用户请求写的数据还未写完,就一直写。
所以说LT同时支持阻塞I/O和非阻塞I/O,而ET模式只能支持非阻塞I/O。
区别
1、支持一个进程所能打开的最大连接数
select:单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。
poll:poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的。
epoll:虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。
2、FD剧增后带来的IO效率问题
select:因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。
poll:同上
epoll:因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。
3、 消息传递方式
select:内核需要将消息传递到用户空间,都需要内核拷贝动作
poll:同上
epoll:epoll通过内核和用户空间共享一块内存来实现的。
http与https的区别,加密怎么加?
HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议
它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换,简单来说它是HTTP的安全版。
http与https的区别在于
http一般使用的是80端口,而https使用的是443端口
https协议需要ca证书
http是明文传输的,而https是通过ssl加密之后传输的。
https使用的是非对称加密,所谓的非对称加密就是加密密钥与解密密钥是不相同的。