在使用HttpClient调用后台resetful服务时,在使用HttpClient调用后台resetful服务时,“Connection reset”是一个比较常见的问题,有同学跟我私信说被这个问题困扰很久了,今天就来分析下,希望能帮到大家。例如我们线上的网关日志就会抛该错误:“Connection reset”是一个比较常见的问题,有同学跟我私信说被这个问题困扰很久了,今天就来分析下,希望能帮到大家。例如我们线上的网关日志就会抛该错误:

从日志中可以看到是Socket套接字在read数据时抛出了该错误。

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

可能有同学对复位标志“RST”还不太了解,这里简单解释一下:

TCP建立连接时需要三次握手,在释放连接需要四次挥手;例如三次握手的过程如下:

  1. 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;

  2. 第二次握手:服务器收到syn包,并会确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

  3. 第三次握手:客户端收到服务器的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的配置代价很大(所有后台服务都需要修改);所以这里并没有使用长连接。ping服务器的时间如下图:

最后的解决方案是客户端和服务器统一使用TCP短连接:我这边正是这么干的,而使用短连接既不用改nginx配置,也不用改tomcat配置,只需在使用HttpClient时使用http1.0协议并增加http请求的header信息(Connection: Close),源码如下:

httpGet.setProtocolVersion(HttpVersion.HTTP_1_0);
httpGet.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);

最后再补充几句,虽然对于每次请求TCP长连接只能节约大约1ms的时间,但是具体是使用长连接还是短连接还是要衡量下,比如你的服务每天的pv是1亿,那么使用长连接节约的总时间为:

1亿*1ms=10^8*1ms=10^5*1s=10^5*1h/3600≈27.78h

神奇的是,亿万级pv的服务使用长连接一天内节约的总时间为27.78小时(竟然大于一天)。

所以使用长连接还是短连接大家需要根据自己的服务访问量、扩展性等因素衡量下。但是一定要注意:服务器和客户端的连接一定要保持一致,要么都是长连接,要么都是短连接。

什么是我的java.net.SocketException:连接重置?相关推荐

  1. java中异常+连接重置_java.net.SocketException:连接重置

    你应该仔细检查完整的痕迹, 我有一个服务器套接字应用程序并修复了 java.net.SocketException: Connection reset 案例 . 在我的情况下,它发生在从clientS ...

  2. java中异常+连接重置_是什么导致我的java.nett.ocketException:连接重置?

    是什么导致我的java.nett.ocketException:连接重置? 我们看到了频繁但断断续续的情况.java.net.SocketException: Connection reset我们日志 ...

  3. CentOS6中连接ftp服务器下载文件时出现了java.net.SocketException: Connection reset

    问题描述:连接CentOS6中的ftp服务器下载文件时出现了java.net.SocketException: Connection reset 解决办法: 1.查看防火墙状态,发现防火墙已开启 se ...

  4. java中socket被拒绝_JavaMail API到iMail – java.net.SocketException:权限被拒绝:连接...

    JavaMail API到iMail – java.net.SocketException:权限被拒绝:连接 我无法使应用程序使用JavaMail API以比以前更自动化的方式发送一些文件. 我对Ja ...

  5. android程序在调试时出现了套接字异常“java.net.SocketException: Permission denied”该如何解决...

    Socket不能对外连接,错误不会被报出,调试的时候,能看到Exception, 一般是抛出 java.net.socketexception permission denied这个异常.只要你的程序 ...

  6. JedisConnectionException: java.net.SocketException: Broken pipe

    问题:redis一台,内存15g,32个现成共同操作redis!数据量160w,报出:JedisConnectionException: java.net.SocketException: Broke ...

  7. java.net.SocketException: 断开的管道 (Write failed) 错误,数据库隔一段时间就断开的问题...

    一个项目使用了druid作为数据源,每过几十分钟刷新页面就会出现 java.net.SocketException: 断开的管道 (Write failed) 错误. 后来给连接池配置部分加上了 &l ...

  8. java 链接占用太多_Java程序链接数过多导致java.net.SocketException: No buffer space available问题...

    发布时间: Aug 29, 2020 更新时间: Aug 29, 2020 总字数:482 阅读时间:1m 作者: 谢先斌 Java程序链接数过多导致java.net.SocketException: ...

  9. java.net.SocketException四大异常解决方案---转

    java.net.SocketException如何才能更好的使用呢?这个就需要我们先要了解有关这个语言的相关问题.希望大家有所帮助.那么我们就来看看有关java.net.SocketExceptio ...

最新文章

  1. Tomcat单机多实例
  2. 为什么csdn搜索自己文章时,加了英文分号的搜索不了?“ ' ”
  3. 为什么CRM Opportunity的删除会触发一个通向BW系统的RFC
  4. opengles 顶点数组 android,OpenGLES顶点属性、顶点数组和缓冲区对象
  5. java 键入_在Java中键入Safe SQL
  6. C++ vector类详解
  7. 基于气动人工肌肉的双足机器人关节设计
  8. Python Flask 中的路由
  9. 2000条你应知的WPF小姿势 基础篇69-73 WPF Freeze机制和Template
  10. 干货 | PyTorch常用代码段整理合集
  11. 零基础自学SQL课程 | SQL中的日期函数大全
  12. 深度神经网络的优化算法,深度神经网络算法原理
  13. 计算机键盘怎么换键,电脑键盘快捷键怎么更改
  14. 进程调度案例分析:为何不能调度?
  15. android html footer 固定,footer保持在页面底部的两种方法
  16. [读书笔记] 蔡康永的说话之道
  17. 2006东京游戏展游历
  18. 【文章阅读】The Devil is in the Decoder【计算机视觉中的上采样方式-6种】
  19. FICO配置详解之五:内部订单管理
  20. 网神综合能力过硬 服务水利系统信息化

热门文章

  1. NOJ1076机器狗组装费用——诡异的运行时间
  2. JDK11你必须了解的新特性
  3. PMP证书要怎么考,含金量怎么样?
  4. 子集生成(二进制法,逐步生成,递归增量)
  5. PEANUT-WF模块开发-Peanut.Common
  6. python 拼音汉字和识字,python-pinyin
  7. ABBYY FineReader 14的新增功能有哪些?
  8. 【愚公系列】2022年03月 微信小程序-富文本编辑器
  9. [Unity]如果AssetStore的下载无效怎么办
  10. 数据库中的Schema(模式)和View(视图)