作者回复: 这是内核的行为。close()系统调用会走到tcp_close(),在这个函数里,会做判断,如果buffer里还有数据未读,它就直接调用tcp_send_active_reset(),发出RST,并把这个连接直接设置到CLOSED状态,也就是不进入TIME_WAIT。 对于这种情况,为了避免close()时候发出RST,就需要检查业务代码,确保在调用close()之前,把接收缓冲里的数据读取掉。
作者回复: 答案是tcp.flags.ack == 1 and tcp.flags.reset == 1 tcp.ack是指报文的确认号,是一个数字 tcp.flags.ack和tcp.flags.reset都是报文的TCP标志位,不是0就是1
作者回复: 你好,这个要看具体的场景逻辑,有一种场景就是握手的第三个报文是RST+ACK的,那就是健康检查,也就是对服务端口的可达性的检查。发起端发送SYN,服务端回复SYN+ACK,发起端此时知道这个服务端口是可用的(健康的),此时探测任务已经完成了。而用RST+ACK的话可以明确的让服务端关闭这个连接请求(释放资源),在发起端(客户端)也是可以回收资源,对双方都有利。
作者回复: 是的,就是确认它收到的上一个报文。在TCP里面,基本上除了握手的第一个报文SYN,其他报文都带ACK标志位
作者回复: 您好,这确实是一个有意思的话题。TCP确实可以做“半关闭”行为,但是仅根据对端发出的一个FIN报文是无法确切的判定对端是全关闭(同时关闭读和写)还是半关闭(只关闭写)的。但是对端在FIN报文后的行为倒是可以帮助我们做进一步的判断。 比如你遇到的情况是,收到FIN后,你继续发送数据,对端回复了RST。这大概率说明对端是同时关闭了读和写了。也就是说,对端发出FIN的同时,它这个socket已经既不能写入数据(也就是发给你数据),也不能接受数据(也就是接收你在收到FIN后发送的更多的数据报文)了。由于此时对端这个socket处于这种不可读写的状态,所以当对端的内核收到了你的数据报文时,它就用RST做了回复。 当然,如果对端的FIN是由shutdown(sockfd, SHUT_WR)触发的,那就只是关闭写的方向,也会同样发送FIN给你,而此时你继续发送数据报文,对端还是有可能会接收的。总之还是看具体的代码场景了~ 所以我推测,对端当时是用shutdown(sockfd, SHUT_RDWR)或者close(sockfd)来关闭这个连接的。供你参考。
作者回复: 这个图是Stevens的书中的原图。之前没留意,你这么说,我觉得真是个问题。服务器发送的FIN的seq应该是L加上最后一次data的length。你好仔细!~
作者回复: 你好,这次的抓包细节是这样的: “所以,我们就展开了抓包工作。具体做法是:我们需要选择一端做抓包,这次是客户端;检查应用日志,发现没几分钟就出现了 connection reset by peer 的报错;对照报错日志和抓包文件,寻找线索。” 对应你的几个问题: 如何抓包:用tcpdump 在哪端抓包:客户端 抓包时间点:这个没有特别的讲究,因为问题一直在发生,随时可以抓 过滤条件: tcpdump host 服务端IP 抓了几分钟就发现日志里有我们找的报错,此时就可以把抓包停止了。因为很容易复现,所以抓包时间不长,只有3分25秒。具体的抓包示例文件我很快上传:)
作者回复: 是的,抓包分析入门后会发现越来越多的乐趣:)
作者回复: 您好,后面从第6讲开始大部分都有抓包示例文件了,供你参考~ 这一讲的文件我整理一下:)
作者回复: openrestry我了解不多,不过从协议来看,你在openrestry网关上看到很多TW,那就意味着网关主动发起了关闭,你的这个判断是正确的。 你的测试场景是不是这样:Jmeter -> F5 -> openrestry 你这里提到“用的都是短连接”,应该是指JMeter或者F5做了这个配置对吧,那么按照http协议规范,如果客户端(这里是Jmeter或者F5)发送的http请求里面携带Connection: close头部,web server(这里是openrestry)有可能会主动发起关闭。我这里说“有可能”是因为我也注意到有些web server并不会那么做,也许是考虑到了主动关闭会引发自己进入TW状态,而这种状态的连接越多,对web server自己越不利。