网络协议其实就是端到端的一个通信规则,有了这些规则,双方的沟通才有意义。
其中,有几点比较重要:
序列号(seq)
:数据包的序号,通过序号来确认包的连续性,解决包的乱序问题。响应号(ack)
:针对上面字段的确认序号,比如服务器接收到客户端的请求,里面包含了 seq 序号,此时服务器响应回去时,会进行 ack = seq + 1 的字段设置,表示已接收到的累积数据。Window
:滑动窗口使用,用来反馈接收方接下来能处理的包大小,防止双方对数据包的处理能力不对等,主要解决了流控问题。TCP Flag
:TCP 包的类型,用来辅助 TCP 的阶段处理,比如 SYN 表示建立连接,FIN 表示关闭连接。如果我们只进行 2 次握手就建立连接,那么对于 Server 端来讲太容易建立起连接了,基本是有客户端过来,那么 Server 就要建立起连接了。这种情况就会导致连接成本太低,Server 端很容超负载。
四次挥手是因为 TCP 是全双工
的,存在了数据发送与接收两个行为,在这两个方向的数据流入流出都需要进行关闭。
当服务接收到客户端请求连接 SYN,然后向客户端响应 ACK 和 SYN 后, 就会将连接维护到半连接队列。当客户端再次回复 ACk 后,当前的连接就会被维护到全连接队列里。
SYN 攻击是 DOS 攻击的一种,通过伪造大量的请求建立连接,使得半连接队列超出最大容量,其他正常的请求无法处理。
TIME_WAIT
是一个定时设置,在 2*MSL(MSL 表示一个包在网络环境中的生存时间,一般为 2 分钟, Linux 里为 30s)时间过后就会真正的 CLOSED。
之所以不立即关闭,主要为了让被动关闭方能有足够的时间接收到最后的 Ack 包,如果没有接收到,被动方就会重新发送 Fin 包,重新触发主动方发送最后的 Ack 包。这样的话,就能尽量保证被动关闭方尽快关闭连接了,毕竟主动关闭方需要承担起主要责任,所以会有 TIME_WAIT 的等待了。
另外一个原因也是怕当前连接立马释放,有一定概率会重用到当前连接标识(五元组),而旧的网络包由于延迟此时才接收到,就有可能产生包的混乱问题了。
TCP 发送的包都需要接收方进行一个 Ack
包的响应,如果在一定时间内没有响应的话,那么发送方就会认为包未能正确到达,需要进行重传动作。这就是 TCP 的重传机制。
TCP 里的重传机制会有一个超时的判断,这个超时时间并不是很准确,或者说并不是很标准,毕竟不同的网络环境,包的到达情况都会是不一样的。
所以 TCP 会使用一个采样时间,先记录了正常情况下一个数据包从发送到响应确认这么一来一回的时间,即所谓的 RTT
(Round Trip Time) 时间,根据这个时间进行一些公式计算,得到了超时时间的值:RTO
(Retransmission TimeOut)
对于重传机制,还有另外一种触发机制。上面的情况属于发送方去探知发送情况,有另一种情况是接收方能探知的。比如发送方发送了 1, 2, 3 的包,但实际上接收方只接收到 1 和 3,一直没能收到 2 这个包,那此时接收方就会连续响应三个 关于 2 的 ack 包。
当发送方收到这么一个连续的 3 个 ack 包后,就知道需要重传 2 了,此时就不需要等到 2 的超时未确认触发,可以提前的重传 2 这个包了。
TCP 采用滑动窗口
进行了流量的控制,所谓的滑动窗口即在发送方和接收方各自维护了一个窗口,在这个窗口里将会维护对应的数据包,以感知当前的数据处理情况。
在接收方这边的窗口称之为接收窗口
,它具体表示当前所能接收的数据包大小,计算公式为:当前最大可接收缓冲区大小 - 当前已接收的大小,在连接建好的开始一般为 65535 字节。
在计算出可接收大小后,接收方就会将此值设置在 TCP 头部里的 Window 字段,然后响应回发送方,发送方也就知道了当前所能允许发送的数据包大小了。
在发送方这边的窗口称之为发送窗口
,按正常逻辑来讲,发送窗口维护的是即将要发送的数据,即根据刚刚反馈回来的接收窗口大小计算出的发送数据。
但由于一个数据包的发送需要有一个 ACK 响应才算完整流程,所以对于这些“已发送未响应”的数据也应该纳入到发送窗口的管理,并且只有真的 ACK 响应回来,才能继续下个数据包的准备发送。
需要注意的是,如果发送方接收到的 Window 大小为 0,则表示当前的接收方已经无能力处理新的包了,此时发送方就不会再下发数据了,直到接收方发送一个窗口通告
,才继续数据的发送。
但此时需要考虑一种情况,就是接收方由于网络问题没能将窗口通告送达发送方,那此时发送方就会一直干等着了.所以对于发送方来讲,会启动窗口探知动作,要求接收方 ACK 它当前的接收窗口大小,如果超过 3 次的探知动作,则直接断开连接了。
TCP 协议抽象出了拥塞窗口
(cwnd)的概念,它会根据当前的网络拥塞程度进行动态的调整。由于加入了拥塞情况的考虑,上面我们提到过的发送窗口则不能仅仅只考虑接收窗口这个因素了,需要进行 min(拥塞窗口,接收窗口)
的选择发送了。
MSS 表示 网络传输数据的最大值,如果 MSS 加上包头大小,则表示网络传输最大报文:MTU 。
在 Internet 这种互联网中,一般 MTU 定义为 576 字节,减去 TCP、IP 的包头 40 字节,则可以得到 MSS = 536 字节的值;而在以太网这种局域网里,一般 MTU 会大点:1500 字节,MSS 为 1460 字节。
当连接建立完毕,开始传输数据时,TCP 协议规定不能一开始就发送大尺寸的数据包,这样避免了网络环境有问题时,新加入的连接加剧了拥塞状况。所以,对于新加入的连接而言,需要一点一点的增大数据量,这就是所谓的慢启动
。
其中,慢启动涉及的拥塞窗口计算过程如下:
从慢启动的算法来看,每经过一个 RTT 后,拥塞窗口的增长速度将会变得很厉害,如果没有进行限制的话,那么很快就会占满带宽了。因此, TCP 协议使用了一个叫慢启动门限(ssthresh)的变量(一般取 65535 字节)。当 cwnd(拥塞窗口) 超过该限制后,就会进入所谓的拥塞避免
阶段了。
在拥塞避免阶段,拥塞窗口的计算过程如下:
从上面的算法可以看出,进入拥塞避免阶段后,数据包的发送大小将呈线性增加了。通过这样的方式,使得 TCP 的传输在前期很快,然后再慢慢降下来,达到网络最佳值。
在拥塞发生时,关于拥塞窗口的计算在不同的 TCP 版本里将会不一样,主要有以下 3种版本:
Tahoe 版本是 TCP 的最早版本,当它发现需要进行重传动作,即触发了 RTO 超时或发送方收到三个重复 ACK 包时,此时会进行的动作为:
Reno 版本进行的动作为:
其中,快速恢复阶段的计算又如下:
NewReno 是对 Reno 的改进,主要是优化了快速恢复阶段,在 Reno 版本中,所考虑的都是一个包的丢失情况。然而,在实际情况中,一次数据窗口的发送,是有可能出现很多数据包丢失情况的。
这样的话,就会触发多次的 cwnd 和 ssthresh 减半动作,一旦 cwnd 降到小于 3 时,即发送窗口会出现小于 3 的情形,此时将再也触发不了 3 次快速重传动作了,只能依赖 RTO 超时,而一般 RTO 的值是比较大(太小会经常触发重传)的,此时整个传输速度将会大大降低。
所以 NewReno 会在收到所有数据包的确认后才结束快速恢复阶段,这样 cwnd 和 sshthresh 就不会轻易被降低了。
NewReno 主要是使用了一个 recover 变量,作为当前数据窗口中,可能丢包的最大序号。即如果有丢包情况产生,并且大于当前的 recover 值,则会更新该值。
当收到接收方的 ack 后,会进行 ack_seq 的判断,如果 ack_seq > recover,此时就可以结束快速恢复阶段了;如果 ack_seq < recover,则意味着多包丢失,还不能结束快速恢复阶段。通过这样的控制,来提高了整个的吞吐量。
Nagle 算法把多个小数据包合并到一个片段,并且等待满足一定条件后,再一起发送过去。具体的触发条件如下:
当上述条件都未满足,但发生了超时(一般为 200ms),则立即发送。
对于 TCP 协议来讲,默认会启用 Nagle 算法,降低网络负载,减少网络拥塞,提高网络吞吐。
在 TCP 的确认机制里,可以在通信过程中不对每一个 TCP 数据包进行单独的 ACK 包响应,而是在传输数据时,顺便把 ACK 信息随数据包一起发送,这样可以提高网络流量利用率。
如果在一定时间内(一般 40 ms)没有数据包要发送,此时就会单独的进行 ACK 包响应。这个过程也被称为 Delay Ack。
TCP 是面向字节流的传输,它会根据接收方的包处理能力以及当前网络的拥塞情况来一部分一部分的加载数据发送,再加上有 Nagle 这种整合小数据包的算法存在。所以对于接收方来讲,接收到的数据有可能是粘合在一起的,也有可能是被拆分开的,即所谓的粘包和拆包。
对于粘包和拆包现象,常用的解决方案有:
TCP 的连接和断开都是双方互相沟通进行的(三次握手、四次挥手)。在数据的传输过程中会进行应答确认、超时重传、流量控制、拥塞控制、拥塞避免等手段去保证传输的准确性。
TCP 是面向字节流的可靠连接,而 UDP 是面向数据报文的连接,不保证可靠连接,但传输比较快。TCP 常用于邮件、文件传输这种要求准确性高的场景,而 UDP 常用于视频直播这种实时传输的场景。
HTTP 是基于 TCP 协议的短连接,按请求-响应来通信。每一次的请求都是独立的,和上次的没有关联。尽管 TCP 是有状态的,但它的状态是为了传输使用,比如报文序号、发送窗口大小等辅助信息,这些和 HTTP 的请求没有关系。
Http 虽然有 keep-alive 字段控制,但那是为了提高传输效率,让此次的请求连接尽量生命周期长些,不至于频繁的建立连接-销毁连接。另外,cookie 会话只是 HTTP 的补充,它是允许关闭或伪造的,并不是协议的通信依赖。
首先,会根据域名进行 DNS 的解析,以获取到服务器的 IP 地址。拿到 IP 地址后将会和服务端进行三次握手,建立 TCP 连接。接着将会按照 HTTP 协议的请求-响应来传输网页内容。最后,TCP 通过四次挥手结束连接。
每次请求-响应都会建立一次 TCP 连接,服务器处理完后就会断开 TCP 连接。后面加了 Connection: keep-alive 来延迟 TCP 连接时长,尽量让请求-响应使用同一个连接
HTTPS 解决了 HTTP 的安全传输问题,在 HTTP 这一层协议下加入了 SSL 层。即进行了端到端的加密/身份验证,以保证数据的不被窃取篡改。
HTTPS 的流程如下:
ping 采用了 ICMP 协议,ICMP 协议用于在 IP 主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
DOS:即拒绝服务,其目的是使计算机或网络无法提供正常的服务。最常见的 DoS 攻击有计算机网络带宽攻击和连通性攻击,像 SYN 洪水攻击也是一种,它利用 TCP 协议发送大量的半连接请求,耗费服务器的 CPU 和内存资源。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。