TCP/IP

TCP

ACK 始终表示接收方期望收到的下一个字节序号,而 SEQ 表示发送方当前发送数据段的字节序号。

全连接队列 (Accept Queue)

存储已经完成三次握手并建立的 TCP 连接,但还没有被应用程序 accept() 调用接收的连接。

当 TCP 连接建立成功后,三次握手完成,连接就被放入全连接队列中,等待服务器应用程序调用 accept() 来取出这个连接。连接一旦从全连接队列中取出,就会成为一个活跃的连接,可以进行数据交换。

半连接队列 (Syn Queue)

存储还未完成三次握手的连接请求,即处于 SYN_RECV 状态的连接。

当客户端发起连接请求,服务器接收到 SYN 包并发送 SYN-ACK 包后,连接会进入半连接队列。此时服务器在等待客户端的 ACK 包,完成三次握手。

什么是 SYN Flood ?

SYN Flood 是一种典型的 DDos 攻击,它在短时间内,伪造不存在的 IP 地址,向服务器发送大量 SYN 报文。当服务器回复 SYN+ACK 报文后,不会收到 ACK 回应报文,那么 SYN 队列里的连接就不会出队,久⽽久之就会占满服务端的 SYN 接收队列(半连接队列),使得服务器不能为正常⽤户服务。

两次握手问题

三次握手可以解决两次握手中旧的历史请求被错误建立连接

情景一:

  • 客户端发送syn(seq = 90),客户端宕机,且syn被网络阻塞
  • 客户端重启,重新发送syn(seq = 100),但是旧的syn(seq = 90)比新的这个先到达服务器
  • 服务器回复syn + ack(90 + 1),客户端收到后(如果是两次握手这里就建立了错误连接)发现不是自己要的ack(100 + 1),所以发起RST(Reset The Connection)报文中止连接
  • 新的syn(seq = 100)到达服务器,服务器回复syn + ack(100 + 1),客户端收到后回复ack,连接建立

情景二:

  • 客户端发送syn(seq = 90),syn被网络阻塞,等待一段时间后客户端发送新的syn(seq = 100)
  • 服务器收到新的syn包,回复syn + ack,如果是两次握手,此时直接建立连接
  • 旧syn包网络恢复,到达服务器,服务器回复syn + ack(90 + 1),又建立一个连接
  • 但是客户端收到这个91的ack不会建立连接(因为它suppose自己应该收到的是101)
  • 此时服务器以为自己有两个连接,而客户端以为自己只有一个连接,造成状态不一致

tcpdump+wireshark抓包分析

首先查看baidu的ip地址

1
2
3
4
5
6
[root@localhost ~]# nslookup www.baidu.com
Server: 8.8.8.8
Address: 8.8.8.8#53

Name: www.baidu.com
Address: 198.18.0.58

使用tcpdump命令开启抓包

1
tcpdump -i any host 198.18.0.58 and tcp -w baidu.pcap

在另一个shell访问baidu

1
curl -I https://www.baidu.com

使用wireshark打开抓包得到的baidu.pcap文件:

抓包分析

可以看到1、2、3是三次握手,16、17、18、19是四次挥手

三次握手时序图

四次挥手时序图

流量控制

  • 滑动窗口:根据接收方的接收能力,AdvertisedWindow,决定发送方发送数据包的窗口大小

拥塞控制

  • 慢启动:拥塞窗口cwnd 从1开始随着收到ACK的数量指数增加,1->2->4->8

  • 拥塞避免:窗口大小超过阈值(65535字节)后,每收到一个 ACK 时,cwnd = cwnd + 1/cwnd

  • 拥塞发生:网络拥塞发生丢包时,有RTO超时重传和快速重传机制

    针对超时重传的拥塞发生算法:阈值 = cwnd / 2,cwnd = 1,进入慢启动算法,有点急刹车的感觉

    针对快速重传的拥塞发生算法:cwnd = cwnd / 2,阈值 = cwnd,进入快速恢复算法

  • 快速恢复:快速恢复算法认为,还有 3 个重复 ACK 收到,说明网络也没那么糟糕,所以没有必要像 RTO 超时那么强烈。

重传机制

  • 超时重传:RTT和RTO,RTT就是数据往返时间,RTO就是超时重传时间,RTO是动态的,略大于RTT,经过大量的实验得出的公式参数计算出来(记忆:时间驱动)
  • 快速重传:当接收方发现丢了一个中间包的时候,连续发送三次前一个包的ACK,发送端收到后就会重传这个包(记忆:数据驱动重传)。缺点就是多个seq包丢失不知道重传哪几个造成的效率低下问题
  • SACK:在 TCP 头部「选项」字段里加一个 SACK 的东西,它可以将已收到的数据的信息发送给「发送方」,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
  • D-ACK:Duplicate-ACK,接受方使用SACK告诉发送方重复接收到了哪些数据

IP

子网掩码

用于确定一个IP地址的网络部分和主机部分,它是一个32位的二进制数字,与IP地址做逻辑与运算,将IP地址划分为网络地址和主机地址两部分。

假设一个公司使用的IP地址段是192.168.0.0/24,24表示IP地址的前24位是网络位,后(32-24=8位是主机位),24对应的子网掩码是:

1
2
11111111 11111111 11111111 00000000
255.255.255.0

网络地址

它是指一个网络的起始地址,用于标识一个特定的网络(这个公司的内部网络)。网络地址用于路由器将数据包发送到正确的网络。在网络地址中,主机部分全为0。

1
2
3
IP 地址:     11000000.10101000.00000000.00000000 -> IP:192.168.0.0
子网掩码: 11111111.11111111.11111111.00000000
按位与操作: 11000000.10101000.00000000.00000000 -> 网络地址:192.168.0.0

广播地址

广播地址在 IP 地址中用于向同一网络内的所有设备发送消息或数据包。它是一个特殊的地址,使得发送到该地址的数据包将被网络上的所有设备接收。

举个例子,假设你的局域网中有四台计算机,它们的 IP 地址范围是:192.168.0.1 - 192.168.0.4,子网掩码为 255.255.255.0。如果你想向整个局域网发送一个广播消息,你可以将目标地址设置为 192.168.0.255,这是该网络的广播地址。这样,所有四台计算机都能够接收到该消息,并根据需要作出响应。

将IP地址的主机位全设为1即可得到广播地址

1
2
3
IP 地址:     11000000.10101000.00000000.00000000 -> IP地址:192.168.0.0
子网掩码: 11111111.11111111.11111111.00000000 -> 255.255.255.0
将IP的后8位全设为1 -> 广播地址:192.168.0.255

因此可以得出,该局域网下的主机IP可以从192.168.0.1~192.168.0.254

DNS

DNS(Domain Name System,域名系统),将人类易于理解的域名(如 www.example.com)转换为计算机能够识别的 IP 地址(如 192.0.2.1

公网/私网/NAT

公网ip:互联网(全球唯一)

私网ip:局域网(常见192.168.)

NAT(网络地址转换):当私网内部的设备需要访问互联网时,路由器会将设备的私网IP地址转换为一个公网IP地址,并在返回通信时将其转换回私网IP地址。

netstat 查看网络相关信息

1
2
3
4
5
6
netstat //显示所有活动的连接
netstat -a //显示所有连接和监听端口
netstat -n //以数字形式显示地址和端口号(不进行DNS解析)
netstat -o //显示与每个连接相关的进程ID(PID)
netstat -p tcp //显示特定协议的连接
netstat -tulnp //Linux特有,显示所有连接和监听端口,带PID和程序名

TCP/IP
https://payfish.github.io/2024/08/28/TCP-IP/
作者
fu1sh
发布于
2024年8月28日
许可协议