网络抓包实战 01——互联⽹:客户端请求是如何到达服务器的
互联⽹是⼈类历史上最伟⼤的发明创造之一,⽽构成互联⽹架构的核⼼在于 TCP/IP 协议。那么 TCP/IP 是如何⼯作的呢,我们先从数据包开始讲起。
1. 数据包
我们以访问⽹易易某一个广告的请求为例:
上图演示了浏览器(作为客户端)发送了了⼀一个 HTTP GET 请求到⽹易广告投放系统
服务器端
域名为
g.163.com
,IP 地址:59.111.160.246
,端⼝为80
)⽽网易广告投放系统返回了了HTTP 302 响应。
从抓包分析(后续专题会有详细讲述)的角度,查看请求响应在 TCP/IP 层面是如何交互的(为简化描述,不涉及 IP 层以下的细节)。
上图每⼀行代表一个数据包的信息,分别为
时间(Time)、原 IP 地址(Source)、目的 IP 地址(Destination)、协议(Protocol)、长度(Length)和数据包信息(Info)。
浏览器作为客户端(192.168.1.100
),发送⼴告请求之前,⾸先需要跟广告投放系统服务器(59.111.160.246
)建⽴连接,⽽建立连接过程是 TCP 来完成的,于是浏览器委托给客户端 TCP 来建⽴连接。客户端 TCP 建立连接的过程是通过三次握⼿
来完成的(图中前三个数据包)。
连接建⽴后,客户端 TCP 通知浏览器可以使⽤连接进行数据通信,于是浏览器准备好 HTTP GET⼴告请求数据,委托给客户端 TCP 发送出去,⽽客户端 TCP 会把这个⼴告请求数据打包成一个数据分段(因为请求⻓度短),委托 IP 把数据分段传递给远端的广告服务器,IP 把这个数据分段再次打包成 IP 数据包(图中第四个数据包)并发送出去。请求数据包经过长途跋涉(经过若干个路路由器器)到达服务器,导航是由 IP 路由来完成的。服务器端 IP 收到这个数据包后,剥离出数据分段传递给服务器端 TCP。服务器端 TCP 收到 IP 传递过来的数据分段,回复 ack 确认,说明服务器端 TCP 收到了这个请求数据分段,然后服务器端 TCP 把这个数据分段拆开,取出数据,通知上层⼴告投放系统,有数据需要处理。
广告投放系统根据通知去取数据,进行HTTP 解析,发现是⼴告请求,于是进行广告请求处理,并构造 HTTP 响应内容,委托给服务器端 TCP 发送给客户端。服务器端 TCP 接收到应用数据后,打包成一个数据分段(因为响应长度短),委托给 IP 发送给客户端。服务器端 IP 把数据分段打包成 IP 数据包并发送出去。响应数据包经过长途跋涉到达客户端,客户端 IP 接收到响应数据包(第六个数据包)后,剥离出数据分段并传递到客户端 TCP。当客户端 TCP 接收到⼴告响应数据分段后,拆开,取出数据,并通知浏览器上层应⽤去接收数据。浏览器根据通知取出响应数据后,做后续的⼴告操作。
整个会话过程,从 TCP/IP 底层来看,都是数据包的传递和处理。数据包是以 TCP/IP 为核⼼的互联⽹的基本处理单位。
了解了这些,我们继续讲述 TCP/IP。
2. TCP/IP 概述
我们以 RFC 1180 中的图作为参考
上图展示了了四层 TCP/IP 协议图,其中 network applications 是应用程序,属于应⽤层;TCP 和 UDP 主要是传输数据,属于传输层,TCP 确保端对端的可靠传输并尽量确保⽹络健康运行,而 UDP 是简单不可靠传输;IP 主要解决路由问题,属于网络层;ARP 是网络地址转换,主要⽤来转换 IP 地址和 MAC 地址,介于数据链路层和网络层之间,可以看成 2.5 层;ENET 在这里是数据链路层,网卡驱动属于这⼀层,主要做具体的介质传输,前⾯示例中的广告请求抓包就是在数据链路层抓取。
值得注意的是,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 为什么被设计成无状态呢?
无状态协议处理简单
通信之前无需建立连接
TCP 已经⾯向连接服务了,IP 层可以委托 TCP 来解决面向连接的问题
由于不带有状态,互联网路由起来更加自由,容错性也更强
值得注意的是,现实中的 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 经验对工作很有帮助。总结如下:
距离越远,延迟越大,重传概率越大
⽹络状况好坏,直接影响应用程序性能
不同环境,采⽤不同的拥塞算法
拥塞控制算法是互联网的精华,是互联⽹大获成功的关键因素之⼀
TCP 是有状态协议,采用异步处理
抓包分析是找到 TCP 相关问题根本原因的利器
TCP 客户端和 TCP 服务器端之间的交互,是应⽤层所有应⽤公共的交互部分,理解了这部分原理,可以解决⼤量TCP 相关问题。
9. IP 经验知识
在 IP 经验知识方面,我们大致总结如下:
数据包选择路径不是固定的,到达的顺序也可能是乱序的
安全过滤,坑多的地⽅
无状态协议,简化互联网架构,是互联网⼤获成功的关键因素之一
IP 层对 TCP 传递过来的数据包很少分片处理
中途设备不仅仅具备路由功能,⽽且还会⼲涉 TCP 会话(灵异问题的温床)
10. 、结束语
TCP/IP⽹络是互联网的基石,了解 TCP/IP 是如何⼯作的,对于我们解决问题是非常有帮助的,下⼀节会充分利用这节所讲的知识进行抓包分析。
版权声明: 本文为 InfoQ 作者【青春不可负,生活不可欺】的原创文章。
原文链接:【http://xie.infoq.cn/article/9919d2c96647e99310bba09ed】。未经作者许可,禁止转载。
评论