一次GET请求的抓包分析
第一次GET请求-成功
初始环境
客户端地址:192.168.0.143,服务端地址:192.168.0.180。
在客户端上执行"curl 192.168.0.180:30080"访问web页面,并抓包如下图所示。
找到对30080端口的访问记录并按下图所示追踪TCP流。其中26780为客户端端口,30080为服务端端口。
对TCP流的追踪结果如下图所示,可分为三部分:建立连接>数据传输>断开连接。
建立连接
该部分属于明显的TCP三次握手流程,属于传输层。
参考TCP三次握手的逻辑图,如下图所示。
- SYN:为发起建立连接标志,用于发起建立连接。
- Seq:为序列号,此处初始值为0。
可以理解为客户端26780向服务端30080端发起了第一次握手。
- ACK:为应答标志。
- ack:为确认号。其值为序列号Seq+1。
可以理解为服务端响应了客户端的上一次握手,同意建立连接,发起了第二次握手。
在第二次握手后,客户端修改序列号Seq为第一次握手中Seq+1,确认号Ack为第二次握手中Seq+1,向服务端发送ACK确认标志,发起第三次握手。
由此,经过三次握手,建立了一条TCP可靠传输。此时客户端和服务端进入ESTABLISHED状态。
数据传输
当建立了可靠的传输后,客户端向服务端表达了自己的诉求,需要访问一个网页。
可以看到,对比前面的三次握手多了一个"Hypertext Transfer Protocol"超文本传输协议,因为HTTP属于应用层协议,自然要对数据包解析的更深(解析至应用层)。
服务端收到客户端的诉求后,向客户端发送ACK应答标志,其中修改序列号Seq为第二次握手中Seq+1,修改确认号Ack为http数据包长度+1。
- PSH:指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
服务端向客户端发送PSH标志,要求客户端尽快处理这个报文段
服务端继续向客户端发送数据,其中修改序列号Seq为上次数据包长度Len+上次序列号Seq。
当数据都发送完毕后,服务端向客户端返回http状态码200,表示本次http请求处理结束。
客户端收到数据后,向服务端发送ACK应答标志,其中修改确认号Ack为上次Ack的值+上次收到的数据包长度Len。
断开连接
- FIN: 为断开连接标志。
当客户端将数据完全接收完毕后,向服务器发送FIN断开连接标志,通知服务器断开连接。
服务端满足断开连接条件后,向客户端发送FIN断开连接标志,同时进入TIME_WAIT状态。
客户端接收到服务端的断开连接信息后,向服务端发送ACK确认标志并断开连接。
第二次GET请求-失败
现象及解决办法
k8s ipvs模式下,curl inner_server_ip:NodePort 时通时不通,且浏览器访问outer_server_ip:NodePort重复访问均正常,且curl pod_ip:Port多次访问均正常
报错
[A new tcp session is started with the same ports as an earlier session in this trace]
[This frame is a (suspected) retransmission]
最终解决方法:
修改服务端的内核参数
vim /etc/sysctl.conf
net.ipv4.tcp_tw_recycle = 0
sysctl -p
参考资料:https://blog.csdn.net/qq_39592858/article/details/125652646