计算机网络(2)
TCP/IP
资源来自:图解网络介绍 | 小林coding (xiaolincoding.com)
为什么是三次握手?不是两次、四次?
因为三次握手才能保证双方具有接收和发送的能力。
原因一:避免历史连接:在两次握手的情况下,「被动发起方」没有中间状态给「主动发起方」来阻止历史连接,导致「被动发起方」可能建立一个历史连接,造成资源浪费。主动方在第三次可以发送连接中止。
原因二:同步双方初始序列号:
- 接收方可以去除重复的数据;
- 接收方可以根据数据包的序列号按序接收;
- 可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道)
原因三:避免资源浪费:和原因一差不多,就是避免建立新的连接
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。
不使用「两次握手」和「四次握手」的原因:
- 「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;
- 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。
初始化的序列号
为什么每次建立 TCP 连接时,初始化的序列号都要求不一样呢?
主要原因有两个方面:
- 为了防止历史报文被下一个相同四元组的连接接收(主要方面);
- 为了安全性,防止黑客伪造的相同序列号的 TCP 报文被对方接收;
既然 IP 层会分片,为什么 TCP 层还需要 MSS 呢?
MTU
:一个网络包的最大长度,以太网中一般为1500
字节;MSS
:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度;
经过 TCP 层分片后,如果一个 TCP 分片丢失后,进行重发时也是以 MSS 为单位,而不用重传所有的分片,大大增加了重传的效率。
SYN 攻击
我们都知道 TCP 连接建立是需要三次握手,假设攻击者短时间伪造不同 IP 地址的 SYN
报文,服务端每接收到一个 SYN
报文,就进入SYN_RCVD
状态,但服务端发送出去的 ACK + SYN
报文,无法得到未知 IP 主机的 ACK
应答,久而久之就会占满服务端的半连接队列,使得服务器不能为正常用户服务。
SYN 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。
避免 SYN 攻击方式,可以有以下四种方法:
- 调大 netdev_max_backlog;当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列
- 增大 TCP 半连接队列;
- 开启 tcp_syncookies;开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接,相当于绕过了 SYN 半连接来建立连接
- 减少 SYN+ACK 重传次数
TCP 连接断开
每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。
这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态
TIME_WAIT 状态?
需要 TIME-WAIT 状态,主要是两个原因:
- 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
- 保证「被动关闭连接」的一方,能被正确的关闭;
序列号和初始化序列号并不是无限递增的,会发生回绕为初始值的情况,这意味着无法根据序列号来判断新老数据
重传机制
超时重传
重传机制的其中一个方式,就是在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的
ACK
确认应答报文,就会重发该数据,也就是我们常说的超时重传。TCP 会在以下两种情况发生超时重传:2RTT(往返时间)
- 数据包丢失
确认应答丢失
每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送
快速重传
快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。
SACK
它可以将已收到的数据的信息发送给「发送方」,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
D-SACK
使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。
- 可以让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了;
- 可以知道是不是「发送方」的数据包被网络延迟了;
- 可以知道网络中是不是把「发送方」的数据包给复制了;
滑动窗口
糊涂窗口综合症
- 让接收方不通告小窗口给发送方
- 让发送方避免发送小数据
拥塞控制
- 慢启动
- 拥塞避免
- 拥塞发生
- 快速恢复
TCP半连接 全连接
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。
模拟 TCP 半连接溢出场景,实际上就是对服务端一直发送 TCP SYN 包,但是不回第三次握手 ACK,这样就会使得服务端有大量的处于 SYN_RECV
状态的 TCP 连接。
SYN 洪泛、SYN 攻击、DDos 攻击。
- 如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
- 若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
- 如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;
如何解决粘包?
- 固定长度的消息;
- 特殊字符作为边界;
- 自定义消息结构。
tcp_tw_reuse
如果客户端(发起连接方)的 TIME_WAIT 状态过多,占满了所有端口资源,那么就无法对「目的 IP+ 目的 PORT」都一样的服务器发起连接了,但是被使用的端口,还是可以继续对另外一个服务器发起连接的。
因此,客户端(发起连接方)都是和「目的 IP+ 目的 PORT 」都一样的服务器建立连接的话,当客户端的 TIME_WAIT 状态连接过多的话,就会受端口资源限制,如果占满了所有端口资源,那么就无法再跟「目的 IP+ 目的 PORT」都一样的服务器建立连接了。
- net.ipv4.tcp_tw_reuse,如果开启该选项的话,客户端(连接发起方) 在调用 connect() 函数时,如果内核选择到的端口,已经被相同四元组的连接占用的时候,就会判断该连接是否处于 TIME_WAIT 状态,如果该连接处于 TIME_WAIT 状态并且 TIME_WAIT 状态持续的时间超过了 1 秒,那么就会重用这个连接,然后就可以正常使用该端口了。所以该选项只适用于连接发起方。
- net.ipv4.tcp_tw_recycle,如果开启该选项的话,允许处于 TIME_WAIT 状态的连接被快速回收,该参数在 NAT 的网络下是不安全的!
HTTPS 中 TLS 和 TCP 能同时握手吗
HTTPS 是先进行 TCP 三次握手,再进行 TLSv1.2 四次握手」,这句话一点问题都没有,怀疑这句话是错的人,才有问题。
「HTTPS 中的 TLS 握手过程可以同时进行三次握手」,这个场景是可能存在到,但是在没有说任何前提条件,而说这句话就等于耍流氓。需要下面这两个条件同时满足才可以:
- 客户端和服务端都开启了 TCP Fast Open 功能,且 TLS 版本是 1.3;
- 客户端和服务端已经完成过一次通信;
三次挥手的假象
当被动关闭方在 TCP 挥手过程中,如果「没有数据要发送」,同时「没有开启 TCP_QUICKACK(默认情况就是没有开启,没有开启 TCP_QUICKACK,等于就是在使用 TCP 延迟确认机制)」,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。
所以,出现三次挥手现象,是因为 TCP 延迟确认机制导致的。
IP
源IP地址和目标IP地址在传输过程中是不会变化的(前提:没有使用 NAT 网络),只有源 MAC 地址和目标 MAC 一直在变化
IP 在 TCP/IP 参考模型中处于第三层,也就是网络层。
ARP 是借助 ARP 请求与 ARP 响应两种类型的包确定 MAC 地址的。
广播地址可以分为本地广播和直接广播两种。
- 在本网络内广播的叫做本地广播。
- 在不同网络之间的广播叫做直接广播。
分类地址
- 优点就是简单明了、选路(基于网络地址)简单。
缺点
- 同一网络下没有地址层次
不能很好的与现实网络匹配
- C 类地址能包含的最大主机数量实在太少了,只有 254 个,估计一个网吧都不够用。
- 而 B 类地址能包含的最大主机数量又太多了,6 万多台机器放在一个网络下面,一般的企业基本达不到这个规模,闲着的地址就是浪费。
环回地址是不会流向网络,比如localhost
IP 协议相关技术
- DNS 域名解析
- ARP 与 RARP 协议
- DHCP 动态获取 IP 地址
- NAT 网络地址转换:网络地址转换 NAT,网络地址与端口转换 NAPT。
- ICMP 互联网控制报文协议:确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。
- IGMP 因特网组管理协