Linux-TCP 出现 RST 的几种情况
导致“Connection reset”的原因是服务器端因为某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志“RST”,然后此时客户端就会提示“java.net.SocketException: Connection reset”。
可能有同学对复位标志“RST”还不太了解,这里简单解释一下:
TCP建立连接时需要三次握手,在释放连接需要四次挥手;例如三次握手的过程如下:
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;
第二次握手:服务器收到syn包,并会确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
可以看到握手时会在客户端和服务器之间传递一些TCP头信息,比如ACK标志、SYN标志以及挥手时的FIN标志等。
除了以上这些常见的标志头信息,还有另外一些标志头信息,比如推标志PSH、复位标志RST等。其中复位标志RST的作用就是“复位相应的TCP连接”。
TCP连接和释放时还有许多细节,比如半连接状态、半关闭状态等。详情请参考这方面的巨著《TCP/IP详解》和《UNIX网络编程》。
前面说到出现“Connection reset”的原因是服务器关闭了Connection[调用了Socket.close()方法]。大家可能有疑问了:服务器关闭了Connection为什么会返回“RST”而不是返回“FIN”标志。原因在于Socket.close()方法的语义和TCP的“FIN”标志语义不一样:发送TCP的“FIN”标志表示我不再发送数据了,而Socket.close()表示我不在发送也不接受数据了。问题就出在“我不接受数据” 上,如果此时客户端还往服务器发送数据,服务器内核接收到数据,但是发现此时Socket已经close了,则会返回“RST”标志给客户端。当然,此时客户端就会提示:“Connection reset”。详细说明可以参考oracle的有关文档:http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html。
另一个可能导致的“Connection reset”的原因是服务器设置了Socket.setLinger (true, 0)。但我检查过线上的tomcat配置,是没有使用该设置的,而且线上的服务器都使用了nginx进行反向代理,所以并不是该原因导致的。关于该原因上面的oracle文档也谈到了并给出了解释。
此外啰嗦一下,另外还有一种比较常见的错误“Connection reset by peer”,该错误和“Connection reset”是有区别的:
服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;
服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。
“Connection reset by peer”如下图所示:
前面谈到了导致“Connection reset”的原因,而具体的解决方案有如下几种:
出错了重试;
客户端和服务器统一使用TCP长连接;
客户端和服务器统一使用TCP短连接。
首先是出错了重试:这种方案可以简单防止“Connection reset”错误,然后如果服务不是“幂等”的则不能使用该方法;比如提交订单操作就不是幂等的,如果使用重试则可能造成重复提单。
然后是客户端和服务器统一使用TCP长连接:客户端使用TCP长连接很容易配置(直接设置HttpClient就好),而服务器配置长连接就比较麻烦了,就拿tomcat来说,需要设置tomcat的maxKeepAliveRequests、connectionTimeout等参数。另外如果使用了nginx进行反向代理或负载均衡,此时也需要配置nginx以支持长连接(nginx默认是对客户端使用长连接,对服务器使用短连接)。
使用长连接可以避免每次建立TCP连接的三次握手而节约一定的时间,但是我这边由于是内网,客户端和服务器的3次握手很快,大约只需1ms。ping一下大约0.93ms(一次往返);三次握手也是一次往返(第三次握手不用返回)。根据80/20原理,1ms可以忽略不计;又考虑到长连接的扩展性不如短连接好、修改nginx和tomcat的配置代价很大(所有后台服务都需要修改);所以这里并没有使用长连接。
正常情况tcp四层握手关闭连接,rst基本都是异常情况,整理如下:
0.使用 ping 可以看到丢包情况
1. GFW
2. 对方端口未打开,发生在连接建立
如果对方sync_backlog满了的话,sync简单被丢弃,表现为超时,而不会rst
3. close Socket 时recv buffer 不为空
例如,客户端发了两个请求,服务器只从buffer 读取第一个请求处理完就关闭连接,tcp层认为数据没有正确提交到应用,使用rst关闭连接。
3. 移动链路
移动网络下,国内是有5分钟后就回收信令,也就是IM产品,如果心跳>5分钟后服务器再给客户端发消息,就会收到rst。也要查移动网络下IM 保持<5min 心跳。
4. 负载等设备
负载设备需要维护连接转发策略,长时间无流量,连接也会被清除,而且很多都不告诉两层机器,新的包过来时才通告rst。
Apple push 服务也有这个问题,而且是不可预期的偶发性连接被rst;rst 前第一个消息write 是成功的,而第二条写才会告诉你连接被重置,
曾经被它折腾没辙,因此打开每2秒一次tcp keepalive,固定5分钟tcp连接回收,而且发现连接出错时,重发之前10s内消息。
5. SO_LINGER 应用强制使用rst 关闭
该选项会直接丢弃未发送完毕的send buffer,可能造成业务错误,慎用; 当然内网服务间http client 在收到应该时主动关闭,使用改选项,会节省资源。
好像曾经测试过haproxy 某种配置下,会使用rst关闭连接,少了网络交互而且没有TIME_WAIT 问题
6. 超过超时重传次数、网络暂时不可达
7. TIME_WAIT 状态
tw_recycle = 1 时,sync timestamps 比上次小时,会被rst
7. 设置 connect_timeout
应用设置了连接超时,sync 未完成时超时了,会发送rst终止连接。
8. 非正常包
连接已经关闭,seq 不正确等
9. keepalive 超时
公网服务tcp keepalive 最好别打开;移动网络下会增加网络负担,切容易掉线;非移动网络核心ISP设备也不一定都支持keepalive,曾经也发现过广州那边有个核心节点就不支持。
10. 数据错误,不是按照既定序列号发送数据
11.在一个已关闭的socket上接收数据
12.服务器关闭或异常终止了连接,由于网络问题,客户端没有收到服务器的关闭请求,这称为TCP半打开连接。就算重启服务器,也没有连接信息。如果客户端向提其写入数据,对方就会回应一个RST报文段。
参考:
转自:http://www.cnblogs.com/lulu/p/4149562.html
Linux-TCP 出现 RST 的几种情况的更多相关文章
- linux磁盘用满的两种情况
首先查看分区的内存使用情况和inode使用情况 第一种情况,内存用完: 我们拿分区sdb5来做实验 查看内存使用情况和inode使用情况: 第二种情况:inode使用完 我们在该分区下创建很多空文件 ...
- 出现RST的几种情况
1.端口未打开,C向S发送SYN,去连接S的端口9820,但是S没有打开9820端口,这个时候S发送RST 2.请求超时,C向S发送SYN,S回复ACK+SYN,如果C从发送SYN到收到S的ACK+S ...
- linux环境下验证码不显示的几种情况
linux环境下验证码不显示的几种情况 gd库扩展没有安装. 查看phpinfo(),看看有没有安装gd库 yum安装gd库或者phpize安装 安装完成后记得重启php-fpm bom头的原因 在生 ...
- unp第七章补充之socket tcp 产生 rst响应的情况
socket tcp 产生 rst响应的情况(属于硬错误) 1. syn发送到服务器主机,但是目的端口并未运行.则产生一个ECONRFUSED错误.客户端立即返回.比如telnet 192.1 ...
- [转]linux tcp/ip调优
LINUX tcp/ip性能调优 On 2011年03月15日, in linux, tips, by netoearth 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接 ...
- 深入理解Linux TCP backlog
本文转载自深入理解Linux TCP backlog 当应用程序调用listen系统调用让一个socket进入LISTEN状态时,需要指定一个参数:backlog.这个参数经常被描述为,新连接队列的长 ...
- 在windows和linux下如何查看80端口占用情况?是被哪个进程占用?如何终止等
一.在windows下如何查看80端口占用情况?是被哪个进程占用?如何终止等 这里主要是用到windows下的DOS工具,点击"开始"--"运行",输入&quo ...
- Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式
Linux就这个范儿 第15章 七种武器 linux 同步IO: sync.fsync与fdatasync Linux中的内存大页面huge page/large page David Cut ...
- linux TCP数据包重传过程----小结
于TCP/IP协议栈的TCP协议的重传功能是由在linux内核源码(net/ipv4/tcp_output.c)中的函数tcp_retransmit_skb()实现的 代码如下: /* This re ...
随机推荐
- Asp.net5 Session Set扩展
关于Asp.net 5 如何使用Session大家可以参考http://www.mikesdotnetting.com/article/270/sessions-in-asp-net-5 和http: ...
- Zindex和png
Z轴在元素设置position为absolute或relative后被激活,起大小由z-index设置,z-index越大,元素位置越靠上.如果多个元素的z-index值相同,那么html标签中后出现 ...
- Hash dump神器 (转)
在Win7 x64位下无压力测试通过. 0 / INTRO========= Quarks PwDump 是一个Win32环境下的系统授权信息导出工具,目前除此之外没有任何一款工具可以导出如此全面的信 ...
- Spiral Matrix II leetcode java
题目: Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. ...
- Ios开发之Category
Category是在不改变已存在类的情况下,对其添加方法来达到对类进行功能扩展的目的. 对类功能进行拓展的时候,我们会有多种方式,比如说可以通过继承也可以进行功能扩展,但是在Category和继承上我 ...
- java根据图片路径下载到服务器方案 (转)
http://www.cnblogs.com/thinkingandworkinghard/articles/5589484.html 平常做的工作中,有一部分是同步数据的.但是同步的过程中碰到个问题 ...
- 转: linux进程地址图解
http://www.cnblogs.com/clover-toeic/p/3754433.html
- Docker-machine创建虚机时停在虚机启动的提示上,并且创建的虚机显示Ip Not found
Docker-machine创建虚机时停在虚机启动的提示上,并且创建的虚机用docker-machine ls 列出来的时候显示Ip Not found, 是什么原因那? [答案] 看这个帖子: ht ...
- Android studio 自己定义打包APK名称
Android Studio打包应用默认生成的apk名称是:app-release.apk .假设我们要让生成的apk名跟我们版本号包名有联系的话.那我们就要自己定义生成的apk名了,要怎么做呢. 我 ...
- LintCode: Combination Sum II
C++ DFS class Solution { public: void help(vector<int> &a, int now, int sum, int target, v ...