互联网是人类历史上最伟大的发明创造之一, 而构成互联网架构的核心在于 TCP/IP 协议. 那么 TCP/IP 是如何工作的呢, 我们先从数据包开始讲起.
1, 数据包
一, HTTP 请求和响应步骤
http 请求全过程
请求
响应
以上完整表示了 HTTP 请求和响应的 7 个步骤, 下面从 TCP/IP 协议模型的角度来理解 HTTP 请求和响应如何传递的.
2,TCP/IP 概述
我们以 RFC 1180 中的图作为参考
上图展示了四层 TCP/IP 协议图, 其中 network applications 是应用程序, 属于应用层; TCP 和 UDP 主要是传输数据, 属于传输层, TCP 确保端对端的可靠传输并尽量确保网络健康运行, 而 UDP 是简单不可靠传输; IP 主要解决路由问题, 属于网络层; ARP 是网络地址转换, 主要用来转换 IP 地址和 Mac 地址, 介于数据链路层和网络层之间, 可以看成 2.5 层; .NET 在这里是数据链路层, 网卡驱动属于这一层, 主要做具体的介质传输, 前面示例中的广告请求抓包就是在数据链路层抓取.
值得注意的是, ARP 在 Linux 系统里属于网络层, 而在 RFC 里是介于数据链路层和网络层之间. 在《TCP/IP 详解》一书里, ARP 被放到了数据链路层. 当解决实际问题的时候, 我们应该把 ARP 放到网络层.
上图给出使用 TCPCopy 在不同层发包的使用方法. 如果 TCPCopy 从数据链路层发包, 由于没有享受到 ARP 服务, 用户需要在使用 TCPCopy 的时候额外加上 Mac 地址; 而如果 TCPCopy 从 IP 层发包, 则无需指定 Mac 地址.
本课程主要讲述 TCP 相关案例, 没有特殊说明的话, TCP 特指传输层的 TCP.
3, 什么是 TCP
TCP 即传输控制协议, 是一种面向连接的, 可靠的, 基于字节流的通信协议. TCP 的主要工作是定义端口标识应用程序的身份, 实现端对端的可靠通信, 并进行拥塞控制, 防止互联网崩塌.
TCP 有如下关键特性:
由于 TCP 是面向连接的协议, 所以是一种有状态的协议, 而有状态的协议往往比较复杂, 因此 TCP 学习起来也比较困难.
通过状态图来查看一下 TCP 状态的复杂性:
上图展示了错综复杂的 TCP 状态图, 然而现实更加复杂.
现实中的 TCP 状态图其实是这样的:
图中, 不仅 SYN_RCVD 状态能够收到 reset 数据包 (图中 RST,reset 数据包是重置连接的数据包, 可以使 TCP 状态瞬间变为 CLOSED 状态, 而 CLOSED 状态是无法追踪的), 而且 FIN_WAIT1,FIN_WAIT2,ESTABLISHED,SYN_SENT 和 CLOSE_WAIT 都能被 reset 数据包打回到 CLOSED 状态. 不仅如此, TCP 状态还受到超时的影响. 例如 Linux 系统, 一旦连接处于 FIN_WAIT_2, 在 60 秒内(默认) 如果没有接收到对端的 FIN 数据包, 系统会把此连接状态 FIN_WAIT_2 直接变到 CLOSED 状态. 虽然 Linux 这样做是为了防止攻击, 但这种超时就干掉连接状态的做法, 很可能误杀了很多正常连接, 从而使问题更加捉摸不定.
在互联网领域, 很多诡异的问题跟 TCP 状态有关系, 课程后续会有较多案例来讲述这些灵异问题.
4, 端口
当我们去连接服务器程序时, 需要指明服务器端口. 为什么需要端口呢? 因为系统是通过端口来区分不同应用程序, TCP 通过端口找到上层应用.
需要注意的是, 端口号是有限的, 端口号最大为 65535, 能够利用的端口数量随配置而定. 例如在压力测试过程中, 一台机器可以利用的 TCP 端口是有限的, 能够利用的连接 (客户端端口, 客户端 IP, 服务器应用端口, 服务器 IP 地址) 是有限的. 为了解决这个问题, 可以配置多 IP 地址来扩大可用连接数量. 系统支持同一个端口, 不同的 IP 地址来绑定不同的应用. Linux 高版本系统下, 在绑定同一个 IP 地址的情况下, 我们还可以利用 REUSEPORT 机制使不同应用程序共享同一个监听端口, 这对高性能服务器开发是非常有用的. 我们开发的数据库中间件 cetus 就利用这个机制来解决短链接风暴的问题.
5,IP
网络层的主要工作是定义网络地址, 区分网段, 子网内 Mac 寻址, 对不同子网的数据包进行路由. IP 的主要作用就是在复杂的网络环境中将数据包发给最终的目标地址.
IP 是面向无连接的, 是无状态的协议. IP 为什么被设计成无状态呢?
1. 无状态协议处理简单
2. 通信之前无需建立连接
3. TCP 已经面向连接服务了, IP 层可以委托 TCP 来解决面向连接的问题
4. 由于不带有状态, 互联网路由起来更加自由, 容错性也更强
值得注意的是, 现实中的 IP 层往往都带有安全过滤, 甚至有些路由器, 防火墙等中途设备还会干涉应用(例如通过 reset 数据包来干涉 TCP 会话), 为了更好的做安全检测, IP 层还增加了 connection tracking, 在无状态协议上面来追踪上层连接. 这种方式提高了安全性, 但有时也会带来新的问题, 我们后面有案例具体讲述 connnection tracking 带来的坑的故事.
6,TCP Socket
应用程序通过 TCP socket 接口来调用 TCP 服务, 从而达到传递数据的目的. 每一个 TCP socket 会被绑定到一个端口, TCP socket 双向都可以通信, 在发送数据的同时, 还可以接收数据.
值得注意的是, 应用程序发送完数据, 只代表通过 TCP socket 委托给 TCP 的工作已经完成, 不代表发送给对端完毕, 应用发送数据和 TCP 传输数据不是同步的.
7,How TCP/IP Works
当用户通过 TCP socket 接口发送请求后, TCP 协议模块接管了请求传递, TCP 先把请求拆分成一个个更小的数据分段(假设 TCP offload 没有开启的情况下), 通过 IP 层发送出去. 在 IP 层, 这些数据分段会被封装成 IP 数据包, 通过数据链路层发送给互联网(见下图). 这些数据包经过互联网的多个路由器到达目的地. 由于 IP 网络是无状态的协议, 每一个数据包走的路径可能不一样, 而且到达的顺序也有可能不一样, 这就要求对端的 TCP 需要重新组装数据包, 以确保向应用层传递的数据是用户能够识别的用户请求, 这样服务器应用程序就可以处理用户发起的请求了.
下图中, 假设用户请求拆分成两个 IP 数据包
第一个 IP 数据包可能经过 A,B,C,G, 如下图.
第二个数据包可能经过 A,B,E,G(在 B 点选择了 E 节点, 导致路径不同), 如下图.
导致数据包在 B 节点走向不同路径的原因可能有很多种, 例如 C 节点暂时不如 E 节点通畅或者临时发生了网络拥塞, 这与在高速道路驾驶的原理差不多.
由于网络环境多变, 还可能第二个数据包先到达服务器, 这时 TCP 会负责处理 out of order 的情况; 如果网络传递过程中, 某一个路由器由于过于繁忙, 把第一个数据包丢了, 那么客户端的 TCP 会负责重传第一个数据包, 确保服务器端的 TCP 能够不会因为丢包而收不到第一个数据包.
如果用户请求内容很大, 如上传一个大文件, 就会被拆分成大量数据分段, 而 TCP 传输这些数据分段的时候, 往往还会考虑整个互联网能够接收的程度和对方能够接收的程度, 发送数据过于贪婪不仅会连累整个互联网, 对方也未必能够接收得了, 而且还可能使自己速度更慢, 这有点像道路驾驶一样, 不能过于自私, 遵守一定的交通规则才能使道路通畅. 在互联网传输数据方面, 这些交通规则算法就是赫赫有名的网络拥塞控制算法, 而对方能否接收得了, 则通过发送窗口的方式进行控制. 总体来说, 一次发送数据的大小是根据对方的接收窗口大小和拥塞控制算法来综合决定的.
从上面可以看出, IP 负责在互联网传输数据, 而 TCP 负责数据传输可靠并且尽量使网络健康运行, 两者合作完成了请求的传递, 这也是互联网应用工作的普遍方式.
需要注意的是, TCP 负责跟 TCP 进行交互, 应用层无需去实现 TCP 的功能, 只需要委托给 TCP 来完成数据传输, 这种隔离的方式给应用层的开发 / 运维 / 测试带来了方便, 另外, 当出现 TCP 相关问题时, 解决问题的难度也大大增加.
8,TCP 经验知识
在多年实战过程中, 我们发现以下 TCP 经验对工作很有帮助. 总结如下:
1. 距离越远, 延迟越大, 重传概率越大
2. 网络状况好坏, 直接影响应用程序性能
3. 不同环境, 采用不同的拥塞算法
4. 拥塞控制算法是互联网的精华, 是互联网大获成功的关键因素之一
5. TCP 是有状态协议, 采用异步处理
6. 抓包分析是找到 TCP 相关问题根本原因的利器
7. TCP 客户端和 TCP 服务器端之间的交互, 是应用层所有应用公共的交互部分, 理解了这部分原理, 可以解决大量 TCP 相关问题.
9,IP 经验知识
在 IP 经验知识方面, 我们大致总结如下:
1. 数据包选择路径不是固定的, 到达的顺序也可能是乱序的
2. 安全过滤, 坑多的地方
3. 无状态协议, 简化互联网架构, 是互联网大获成功的关键因素之一
4. IP 层对 TCP 传递过来的数据包很少分片处理
5. 中途设备不仅仅具备路由功能, 而且还会干涉 TCP 会话(灵异问题的温床)
10, 结束语
TCP/IP 网络是互联网的基石, 了解 TCP/IP 是如何工作的, 对于我们解决问题是非常有帮助的.
来源: http://developer.51cto.com/art/201908/601541.htm