04 | 挥手:Nginx日志报connection reset by peer是怎么回事?
该思维导图由 AI 生成,仅供参考
在应用层和网络层之间搭建桥梁
- 深入了解
- 翻译
- 解释
- 总结
本文通过实际案例介绍了在Nginx日志中出现的"connection reset by peer"错误的排查过程。作者强调了应用层和网络层信息的差异,以及两者之间的鸿沟。通过Wireshark的过滤器,详细介绍了如何从原始抓包文件中定位与问题相关的报文,以及如何将应用层信息与网络层信息联系起来,解决类似的网络排查问题。文章还介绍了如何排除握手阶段和挥手阶段的RST报文,以及如何使用frame.time过滤器定位特定时间段内的报文。最终,通过对比TCP流里的应用层数据和Nginx日志中的请求和返回,找到了是哪个RST引起了Nginx报错。整体而言,本文通过实际案例生动地展示了解决"connection reset by peer"错误的方法,对读者进行了技术上的指导和启发。文章还通过第二个案例介绍了TCP挥手过程中的一些特殊情况,提醒读者在理解TCP知识点时需要深入理解,而不是生搬硬套。通过抓包分析,作者抽丝剥茧,定位到具体的问题环节不在Nginx,也不在网络本身,而是在客户端代码这里。这样的分析让写代码的同学可以专心做代码修复,而不用一直怀疑问题在其他环节。整体而言,本文内容丰富,案例生动,对读者进行了技术上的指导和启发。
《网络排查案例课》,新⼈⾸单¥59
全部留言(37)
- 最新
- 精选
- 那时刻请问老师,客户端用 RST 来断开连接并不妥当,需要从代码上找原因。比如客户端在 Receive Buffer 里还有数据未被读取的情况下,就调用了 close()。调用close,是不是应该发fin包呢?什么时候会发rst包?
作者回复: 这是内核的行为。close()系统调用会走到tcp_close(),在这个函数里,会做判断,如果buffer里还有数据未读,它就直接调用tcp_send_active_reset(),发出RST,并把这个连接直接设置到CLOSED状态,也就是不进入TIME_WAIT。 对于这种情况,为了避免close()时候发出RST,就需要检查业务代码,确保在调用close()之前,把接收缓冲里的数据读取掉。
2022-01-19515 - kaixiao7老师,在客户端握手的第三个RST+ACK报文中,为什么会出现RST呢?有哪些情况会出现呢?
作者回复: 你好,这个要看具体的场景逻辑,有一种场景就是握手的第三个报文是RST+ACK的,那就是健康检查,也就是对服务端口的可达性的检查。发起端发送SYN,服务端回复SYN+ACK,发起端此时知道这个服务端口是可用的(健康的),此时探测任务已经完成了。而用RST+ACK的话可以明确的让服务端关闭这个连接请求(释放资源),在发起端(客户端)也是可以回收资源,对双方都有利。
2022-05-0311 - *老师,tcp.ack和tcp.flags.ack有什么不同,为什么问题1的答案是tcp.ack==1 and tcp.flags.reset == 1
作者回复: 答案是tcp.flags.ack == 1 and tcp.flags.reset == 1 tcp.ack是指报文的确认号,是一个数字 tcp.flags.ack和tcp.flags.reset都是报文的TCP标志位,不是0就是1
2022-01-2749 - 奕最后一个图 有个疑问的, 为什么客户端在初始化关闭的时候 除了发送一个 FIN ,还有个 ACK呢,是为了回复上一个服务端发送的数据吗?
作者回复: 是的,就是确认它收到的上一个报文。在TCP里面,基本上除了握手的第一个报文SYN,其他报文都带ACK标志位
2022-01-2535 - 上杉夏香这篇文章的最后一张图,是不是有些瑕疵?进入半连接状态后,服务端继续发送数据,当服务器发送FIN报文的时候,它的seq应该不再是L?
作者回复: 这个图是Stevens的书中的原图。之前没留意,你这么说,我觉得真是个问题。服务器发送的FIN的seq应该是L加上最后一次data的length。你好仔细!~
2022-06-274 - 乌龟爱上金鱼老师您好,对端向我发了fin,我这边ack后没有close,进入closewait,对端现在应该是finwait2,按理来说对端现在只是不向我发送数据了,但是能接受数据,但是我继续向对端发送数据后,对端回复的是reset,这是为什么呀?
作者回复: 您好,这确实是一个有意思的话题。TCP确实可以做“半关闭”行为,但是仅根据对端发出的一个FIN报文是无法确切的判定对端是全关闭(同时关闭读和写)还是半关闭(只关闭写)的。但是对端在FIN报文后的行为倒是可以帮助我们做进一步的判断。 比如你遇到的情况是,收到FIN后,你继续发送数据,对端回复了RST。这大概率说明对端是同时关闭了读和写了。也就是说,对端发出FIN的同时,它这个socket已经既不能写入数据(也就是发给你数据),也不能接受数据(也就是接收你在收到FIN后发送的更多的数据报文)了。由于此时对端这个socket处于这种不可读写的状态,所以当对端的内核收到了你的数据报文时,它就用RST做了回复。 当然,如果对端的FIN是由shutdown(sockfd, SHUT_WR)触发的,那就只是关闭写的方向,也会同样发送FIN给你,而此时你继续发送数据报文,对端还是有可能会接收的。总之还是看具体的代码场景了~ 所以我推测,对端当时是用shutdown(sockfd, SHUT_RDWR)或者close(sockfd)来关闭这个连接的。供你参考。
2022-09-19归属地:上海23 - lxj有一点点小提议,分析一个问题能把如何抓包,在哪端抓包,抓包时间点,过滤条件再交代详细点嘛,感觉分析的粒度太粗了,上下文没有交代清楚
作者回复: 你好,这次的抓包细节是这样的: “所以,我们就展开了抓包工作。具体做法是:我们需要选择一端做抓包,这次是客户端;检查应用日志,发现没几分钟就出现了 connection reset by peer 的报错;对照报错日志和抓包文件,寻找线索。” 对应你的几个问题: 如何抓包:用tcpdump 在哪端抓包:客户端 抓包时间点:这个没有特别的讲究,因为问题一直在发生,随时可以抓 过滤条件: tcpdump host 服务端IP 抓了几分钟就发现日志里有我们找的报错,此时就可以把抓包停止了。因为很容易复现,所以抓包时间不长,只有3分25秒。具体的抓包示例文件我很快上传:)
2022-04-043 - sysho这两个月刚好排查了几个抓包问题,觉得老师这节课讲得真好,看得很爽。
作者回复: 是的,抓包分析入门后会发现越来越多的乐趣:)
2022-04-202 - 邓坤坤老师,请问应用层如何编码才能在发送数据时带上fin flag?从来没见过这种
作者回复: 一般来说,应用层是通过系统调用(像connect, socket, bind, send, close, shutdown等)来跟内核网络做交互的。TCP标志位是无法直接操作的,只能通过系统调用来“间接”的达到目的。比如你要发送FIN flag,那就对socket描述符调用close()。 另外就是用raw socket直接构造报文,但未必是你想要的吧 如果要直接操纵报文,还有一种办法是用
2022-08-01归属地:上海1 - 简迷离老师,案例中的抓包文件能提供下吗?这样单独的看文章分析效果还是有限,能提供下案例抓包文件边看边分析数据包效果更佳,还请老师提供下,谢谢您!
作者回复: 您好,后面从第6讲开始大部分都有抓包示例文件了,供你参考~ 这一讲的文件我整理一下:)
2022-03-271