TCP/IP协议十五问

一、什么是网络层？

TCP 网络分层一般分为四层，当然也有说法是五层

应用层（HTTP）：封装数据包

传输层（TCP）：增加 TCP 头部，包含端口号等信息

网络层（IP）：增加 IP 头部，包含 IP 地址等信息

网络接口层（ARP）：增加以太网头部，包含 MAC 地址等信息

网络分层的优点：

各层独立：限制了依赖关系的范围，各层之间使用标准化的接口，各层不需要知道上下层是如何工作的，增加或者修改一个应用层协议不会影响传输层协议；

灵活性：比如路由器不需要应用层和传输层，分层以后路由器就可以只用加载更少的几个协议层

易于测试和维护：提高了可测试性，可以独立的测试特定层，某一层有了更好的实现可以整体替换掉；

能促进标准化：各层职能清晰，方便标准化；

二、TCP 的三次握手？为什么不是两次或者四次？

客户端向服务端发送 SYN，seq = x；

服务端向客户端发送 SYN，seq = y, ACK = x+1;

客户端向服务端发送 ACK = y+1；

两次不行因为如果只做两次无法确定服务端的接收能力；
两次握手后建立连接，有可能导致由于时延产生的多次连接建立，导致资源浪费；
四次的话没必要，会导致资源浪费。

三、TCP 的四次挥手？为什么不能是三次？

客户端向服务端发送 FIN，seq = x+2，ACK = y+1；

服务端向客户端发送 ACK = x+3；

服务端发送完剩余数据后，再向客户端发送 FIN，seq = y+1；

客户端向服务端发送 ACK = y+2；

三次不行，会导致服务端的 ACK 和 FIN 将延迟发送，如果延迟时间过长，客户端将再次重发断开请求，导致资源浪费。

四、为什么 SYN/FIN 不包含数据却要消耗一个序列号？

凡是需要对端确认的，一定消耗 TCP 报文的序列号；

五、什么是半连接队列？什么是 SYN Flood 攻击？

客户端大量伪造 IP 发送 SYN 包，服务端回复的 ACK+SYN 去到了一个（未知）的 IP 地址，势必会造成服务端大量的连接处于 SYN_RCVD 状态，而服务器的半连接队列大小也是有限的，如果半连接队列满，也会出现无法处理正常请求的情况。

六、TCP 快速打开的原理？

TCP 快速打开（TCP Fast Open，TFO）
TFO 是在原来 TCP 协议上的扩展协议，它的主要原理就在发送第一个 SYN 包的时候就开始传数据了，不过他要求当前客户端之前已经完成过正常的三次握手。

快速打开分为两个阶段：请求 Fast Open Cookie 和 真正开始 TCP Fast Open

TCP Fast Open 的优势
可以利用握手去除一个往返的 RTT 和防止 SYN-Flood 之类的攻击

七、TCP 报文中的时间戳有什么用？

TCP Timestamps Option 由四部分构成：类别、长度、发送方时间戳、回显时间戳

第一用于计算 RTT，第二防止序列号的回绕问题，即使使用的序列号相同，也可以通过时间戳来对不同的包进行区分。

八、TCP 的超时重传时间是如何计算的？

超时重传时间：Retransmission TimeOut， 简称 RTO

经典解决方法
适用于 RTT 较小的情况，SRTT (smoothed round trip time)。
利用最新一次的 RTT 对 SRTT 时间进行更新
SRTT = α × SRTT + (1-α）× RTT

九、TCP 流量控制？

把发送的数据放到发送缓冲区，把接收的数据放到接收缓冲区。通过实际接收缓冲区的大小，控制发送端的发送。
接收端会告知客户端自己接收窗口，也就是接收缓冲区中空闲的部分。

发送端的数据包的状态：

已发送且已确认

已发送未确认的

未发送但接收端可以接受的（接收端有空间接受）

未发送且不可以发送（接收端没空间接收）

发送端速度较慢：存在大量待发送的字节；
发送端速度较快：存在大量待确认的字节；

十、TCP 的 keep-alive 原理？

定时发送探测包来探测连接的对端是否存活，但是 keepalive 默认设置的时间过长，7200s 没有实际意义，一般在应用层做心跳机制。

那什么是心跳机制？
定时向服务端发送消息，能响应服务端的消息

长链接业务场景

游戏

即时通讯
在没有心跳包机制的情况下，网络若掉线，对方不可知；
如果客户端掉线，服务端不知道，还维持链接，就是额外的无效系统开销。

为什么需要心跳包：

在 NAT、防火墙网络中装设备，保存信道记录；

及时发现对方网络断开，以便及时采取措施；

如何实现心跳包

TCP 层面的心跳包，只能够验证网络链接是否异常；

应用层层面的心跳包，验证服务接口是否异常；

为什么不采用 TCP 层面？
应用层的连接如果成功，那么 TCP 所在的传输层必定成功。

十一、TCP 中的端口号？

源端口：本地端口

目标端口：服务器端口
最大 65536 个，所以是 0-65535

以下是一些常见的端口号：

21：FTP（文件传输协议）端口，用于文件上传和下载。

22：SSH（安全外壳协议）端口，用于安全远程登录和执行命令。

25：SMTP（简单邮件传输协议）端口，用于电子邮件传输。

80：HTTP（超文本传输协议）端口，用于 Web 浏览器访问网站。

110：POP3（邮局协议版本 3）端口，用于电子邮件客户端接收邮件。

143：IMAP（互联网消息访问协议）端口，用于电子邮件客户端接收邮件。

443：HTTPS（超文本传输安全协议）端口，用于安全的 Web 浏览器访问网站。

3306：MySQL 数据库端口，用于数据存储和检索。

3389：Microsoft 远程桌面端口，用于远程管理和控制计算机。
这只是一小部分常用的端口号，实际上有许多其他端口号可以用于各种不同的通信协议和应用程序。

十二、TCP 场景问题

问题 1
AB 两个主机之间建立了一个 TCP 连接，A 主机发给 B 主机两个 TCP 报文，大小分别是 500 和 300，第一个报文的序列号是 200，那么 B 主机接收两个报文后，返回的确认号是多少？
500+300+200 = 1000

问题 2
收到 IP 数据包解析后，如何知道应该投递到上层中的哪个协议（是 TCP 还是 UDP）？
IP 报文头中有协议字段，TCP6，UDP17

问题 3
TCP 提供了一种字节流服务，而收发双方都不保持记录的边界，应用程序应该如何提供他们自己的记录标识呢？

应用程序使用自己约定的规则来标识消息的边界，比如有一些使用回车＋换行（“\r\n”），比如 Redis 的通信协议；

十三、TCP 和 UDP 的区别？

TCP 是一个面向连接的、可靠的、基于字节流的传输层协议；
UDP 是一个面向无连接的传输层协议；

面向连接：指的是客户端和服务端的连接，在通信前通过三次握手建立连接；

可靠性：

TCP 有状态：TCP 会精准记录那些数据发送了，哪些数据已被接收，那些数据未被接收，并且保证数据包按序到达，不允许差错；

TCP 可控制：如果遇到丢包或者网络不佳，TCP 会根据具体情况自行调整，控制自己的发送速度或者重发。

十四、Telnet 和 netstat 的用法

检查远端端口是否打开，其语法：telnet [ip] [port]

主要用于查询网络情况，如： netstat -ano

十五、Tcpdump 和 wireshark

用于抓包，例如可以查看三次握手和四次挥手等