Connection reset 原因 接收到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

导致“Connection reset”的其中一个原因是服务器端因为某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志“RST”,然后此时客户端就会提示“java.net.SocketException: Connection reset”。

另一个可能导致的“Connection reset”的原因是服务器设置了Socket.setLinger (true, 0)。但我检查过线上的tomcat配置,是没有使用该设置的,而且线上的服务器都使用了nginx进行反向代理,所以并不是该原因导致的。关于该原因上面的oracle文档也谈到了并给出了解释。

Connection reset by peer

此外啰嗦一下,另外还有一种比较常见的错误“Connection reset by peer”,该错误和“Connection reset”是有区别的:

服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。

解决Connection reset几种方案

前面谈到了导致“Connection reset”的原因,而具体的解决方案有如下几种:

1. 出错了重试;2. 客户端和服务器统一使用TCP长连接;3. 客户端和服务器统一使用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基本都是异常情况,使用 ping 可以看到丢包情况

RST复位标志发送原因几种可能整理如下:

  1. 被GFW拦截

    防火长城(英文名称Great Firewall of China,简写为Great Firewall,缩写GFW),也称中国防火墙或中国国家防火墙,指中华人民共和国政府在其管辖因特网内部建立的多套网络审查系统的总称,包括相关行政审查系统。

  2. 对方端口未打开,发生在连接建立

  3. 全连接队列已满,发生在连接建立

    当全连接队列已满就会根据tcp_abort_on_overflow策略进行处理。

    Linux 可通过 /proc/sys/net/ipv4/tcp_abort_on_overflow 进行配置。

    当tcp_abort_on_overflow=0,服务accept 队列满了,客户端发来ack,服务端直接丢弃该ACK,此时服务端处于【syn_rcvd】的状态,客户端处于【established】的状态。在该状态下会有一个定时器重传服务端 SYN/ACK 给客户端(不超过 /proc/sys/net/ipv4/tcp_synack_retries 指定的次数,Linux下默认5)。超过后,服务器不在重传,后续也不会有任何动作。如果此时客户端发送数据过来,服务端会返回RST。(这也就是我们的异常原因了)

    当tcp_abort_on_overflow=1,服务端accept队列满了,客户端发来ack,服务端直接返回RST通知client,表示废掉这个握手过程和这个连接,client会报connection reset by peer。

  4. close Socket 时recv buffer 不为空

    例如,客户端发了两个请求,服务器只从buffer 读取第一个请求处理完就关闭连接,tcp层认为数据没有正确提交到应用,使用rst关闭连接。

  5. 移动链路

    移动网络下,国内是有5分钟后就回收信令,也就是IM产品,如果心跳>5分钟后服务器再给客户端发消息,就会收到rst。也要查移动网络下IM 保持<5min 心跳。

  6. 负载等设备

    负载设备需要维护连接转发策略,长时间无流量,连接也会被清除,而且很多都不告诉两层机器,新的包过来时才通告rst。

    Apple push 服务也有这个问题,而且是不可预期的偶发性连接被rst;rst 前第一个消息write 是成功的,而第二条写才会告诉你连接被重置,

    曾经被它折腾没辙,因此打开每2秒一次tcp keepalive,固定5分钟tcp连接回收,而且发现连接出错时,重发之前10s内消息。

  7. SO_LINGER 应用强制使用rst 关闭

    该选项会直接丢弃未发送完毕的send buffer,可能造成业务错误,慎用; 当然内网服务间http client 在收到应该时主动关闭,使用改选项,会节省资源。

    好像曾经测试过haproxy 某种配置下,会使用rst关闭连接,少了网络交互而且没有TIME_WAIT 问题

  8. 超过超时重传次数、网络暂时不可达(同3)

  9. TIME_WAIT 状态

    tw_recycle = 1 时,sync timestamps 比上次小时,会被rst

  10. 设置 connect_timeout

    应用设置了连接超时,sync 未完成时超时了,会发送rst终止连接。

  11. 非正常包

    连接已经关闭,seq 不正确等

  12. keepalive 超时

    公网服务tcp keepalive 最好别打开;移动网络下会增加网络负担,切容易掉线;非移动网络核心ISP设备也不一定都支持keepalive,曾经也发现过广州那边有个核心节点就不支持。

  13. 数据错误,不是按照既定序列号发送数据

  14. 在一个已关闭的socket上接收数据

  15. 服务器关闭或异常终止了连接,由于网络问题,客户端没有收到服务器的关闭请求,这称为TCP半打开连接。就算重启服务器,也没有连接信息。如果客户端向提其写入数据,对方就会回应一个RST报文段。

  16. TCP在建链过程中收到异常报文时,会发送RST报文:

    如在Listen状态时收到的SYN报文中有ACK标记,SYN_SEND状态时收到SYN|ACK报文中ACK序号不对,etc

  17. TCP在建链时,发出SYN报文之后,60秒之内都没有收到对端的相应报文,会发送RST报文。

  18. TCP报文在连续重传阈值次数之后,都没有收到对端相应报文时,会发送RST报文。(同3、8)

  19. KeepAlive报文在连续发送5次之后,都没有收到对端的KeeAliveReply报文时,会发送RST报文。

  20. 当socket设置了Linger选项,并Linger时间为0时,当调用close来关闭socket时,也会向对端发送RST报文。(同7)

发送RST报文的几种可能的情况相关推荐

  1. dpdk发送RST报文(一)—— 构建RST包

    suricata中阻断报文函数"RejectSendLibnet11IPv4TCP"使用libnet11构造阻断报文.今天试一下自己手动构建RST报文,然后通过dpdk发送出去. ...

  2. TCP/IP详解--接收RST回应的几种情况

    出现RST分节的情况可以在三种情况下发生,在连接建立时.在中间发送数据时.在连接关闭时. 连接建立时出现RST回应的情况有:发送一个不存在的端口,想一个Listen的套接字或者端口上发送数据分节(不是 ...

  3. lwIP 细节之二:协议栈什么情况下发送 RST 标志

    一次网络故障,抓包发现使用 lwIP 协议栈的设备不停的发送 RST 标志,为了探索 lwIP 协议栈什么情况下发送 RST 标志,就有了这篇笔记. 注:除非特别说明,以下内容针对 lwIP 2.0. ...

  4. 报文如何截取时间_5种报文、8种邻居状态机详解OSPF工作原理

    上一章节介绍了OSPF相比RIP具有无环路.路由收敛速度快.可扩展性好的特点.知识卡片 | 链路状态路由协议OSPF凭什么会取代RIP? 我们知道路由协议的最终目的是为了计算最优路由加入路由表来指导I ...

  5. bgp 建立邻居发送的报文_大型网络BGP之IBGP和EBGP邻居关系基础配置

    一.BGP拓扑 说明:BGP一般用于大型企业及国际出口.运营商.大型数据中心 二.BGP基本配置 1.IBGP配置(IBGP属于同一个BGP AS号内部建立邻居关系) 我们在R2 和 R4 之间配置简 ...

  6. Java 用HTTP的方式发送JSON报文请求

    前言: 项目调用第三方接口时,通常是用socket或者http的通讯方式发送请求:http 为短连接,客户端发送请求都需要服务器端回送响应,请求结束后,主动释放链接.Socket为长连接:通常情况下S ...

  7. TCP协议RST:RST介绍、什么时候发送RST包

    一.RST介绍 RST标示复位.用来异常的关闭连接. 1. 发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓冲区中的包,发送RST. 2. 而接收端收到RST包后,也不必发送ACK包来确 ...

  8. 关闭tcp连接时有时发送FIN有时发送RST

    使用http 发送同一个包,sleep 20 秒后再读取数据,htpp设置1s的超时时间,超时后会关闭socket ,可是有时发送RST,有时发送FIN,如下图: 后来google 了一把,发现 tc ...

  9. java 发送tr069报文_TR069报文交互

    TR-069是由DSL论坛(www.dslforum.org)所开发的技术规范之一,其全称为"CPE广域网管理协议".它提供了对下一代网络中家庭网络设备进行管理配置的通用框架和协议 ...

  10. java发送加密报文_RSA加密---从后台到客户端实现报文加解密

    RSA是当前最流行的非对称加密方式,使用公钥加密使用密钥解密,如何妥善的保管密钥就成了关键. 动态生成密钥 工具类 package com.yitong.utils; import java.secu ...

最新文章

  1. C++ dynamic_cast操作符
  2. MFC中的GDI绘图
  3. tensorflow随笔-tf.while_loop
  4. springboot下使用mybatis配置
  5. 基于gRPC服务发现与服务治理的方案
  6. vue Bus 总线 组件间通信
  7. 天人短文网站系统v5.53源码
  8. linux运行tcl脚本语言,Tool Command Language (Tcl)初体验
  9. 基于kickstart实现网络共享以及制作光盘和U盘实现半自动安装centos6系统
  10. [MVC学习笔记]4.使用Log4Net来进行错误日志的记录
  11. 代理服务器基本知识普及代理IP使用方法!
  12. 大话卷积神经网络(CNN)
  13. Python—基于百度AI的人脸识别检索程序(转自本人博客)
  14. 默孚龙电滑环,360度旋转防止绕线
  15. 我所热爱的多触摸系统 bill buxton
  16. 一定要跟你喜欢的人去一次“稻城亚丁”好吗!
  17. 运动耳机什么牌子好、这五款是最值得推荐的运动耳机
  18. ftl模板导出excel_freemarker导出Excel
  19. 单通道图片转换为3通道图片,实现灰度图上添加彩色标注
  20. 利用MUI+个推实现APP消息推送

热门文章

  1. 中国水产科学研究院教授黄樟翰走进伊宅购集团考察伊家田园项目
  2. Java九阳神功-内部类
  3. mysql 内置函数大全 mysql内置函数大全
  4. 安装ie9提示未能完成安装_win10系统安装iE提示“internet Explorer未能完成安装”的方法介绍...
  5. PHP的implode函数运用,PHP implode()函数用法讲解
  6. 小象学院 零基础Python入门 案例四 52周存钱挑战v_3.0
  7. 我该如何拯救你,我的考研?
  8. 九爷带你玩转 php单元测试
  9. 阿里 达摩院 cv 算法 面经
  10. java实现上传寸照并剪裁_Flutter——头像上传功能,实现照片选择及裁剪