资讯专栏INFORMATION COLUMN

HttpClient出现TCP连接异常关闭发送RST包

hersion / 760人阅读

摘要:问题现象在与第三方系统通过交互数据的过程中,抓包发现每次连接都是异常关闭,报文如下可以看到,由我方发起次握手建立连接,然后发送请求,对方响应数据,我方后直接发包图中蓝色阴影部分,将连接异常关闭,不仅没有复用连接,且不是通过次挥手来关闭连接。

问题现象

在与第三方系统通过http交互数据的过程中,抓包发现每次TCP连接都是异常关闭,报文如下:

可以看到,由我方发起3次握手建立连接,然后发送http请求,对方响应数据,我方ACK后直接发RST包(图中蓝色阴影部分),将连接异常关闭,不仅没有复用连接,且不是通过4次挥手来关闭连接。

关于RST包参考:http://blog.csdn.net/erlib/ar...

问题原因

HttpClient 4.5.2 释放连接API使用方式不正确

问题代码如下(已简化):

private boolean isCheckSuccess() {
       CloseableHttpResponse response = null; 
       try {
            // 通过HttpClientBuilder创建CloseableHttpClient
            httpClient = HttpClientFactory.createHttpClient();
            request = initCheckRequest();
            response = httpClient.execute(request);
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)  {
                return true;
            }
        }  finally {
            // 释放连接
            if(request != null) {
                request.releaseConnection();
            }
        }
        return false;
    }

     //构造请求参数
    private static HttpPost initCheckRequest() throws IOException {
        HttpPost request = new HttpPost(callBackUrl);
        request.setHeader("contentType", ContentTypeEnum.JSON.getDesc());
        List params = new ArrayList<>();
        params.add(new BasicNameValuePair("developer_id", "111"));
        params.add(new BasicNameValuePair("sign", "sign"));
        HttpEntity postParams = new UrlEncodedFormEntity(params);
        request.setEntity(postParams);
        return request;
    }

根据释放连接处代码和抓包分析来看,request.releaseConnection(); 每次是发TCP RST包来关闭连接

解决方案

既然是释放连接不对,则修改代码为如下:

finally {
            if(response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                    response.close();
                } catch (IOException e) {
                    logger.error("close http error", e);
                }
            }
        }

正确方式为:
关闭内容流后再关闭响应本身。

如果不关闭IO流,直接response.close(); 则结果是连接不能复用,直接通过4次挥手断开TCP连接。

连接池释放连接的时候,并不会直接对TCP连接的状态有任何改变,只是维护了两个Set,leased和avaliabled,leased代表被占用的连接集合,avaliabled代表可用的连接的集合,释放连接的时候仅仅是将连接从leased中remove掉了,并把连接放到avaliabled集合中

本人blog:https://my.oschina.net/hebaod...

参考

TCP RST相关
http://www.cnblogs.com/JohnAB...
http://blog.csdn.net/erlib/ar...
http://lovestblog.cn/blog/201...
https://my.oschina.net/costax...

HttpClient相关
https://www.cnblogs.com/likai...
http://liangbizhi.github.io/h...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70649.html

相关文章

  • Socket之so_linger与rst

    摘要:滑动窗口滑动窗口毫无疑问是用来加速数据传输的。处理程序会在自己认为的异常时刻发送包。序列号问题是与滑动窗口对应的,伪造的包里需要填序列号,如果序列号的值不在之前向发送时的滑动窗口内,是会主动丢弃的。 看Apache HttpClient的源码时,发现abortRequest的时候,调用到socket时代码如下: public void shutdown() throws IOExcep...

    ashe 评论0 收藏0
  • 服务器TIME_WAIT和CLOSE_WAIT分析和解决办法

    摘要:服务器出现异常最长出现的状况是服务器保持了大量的状态。此时主动关闭一方必须保持一个有效的状态下维持状态信息,以便可以重发。这就意味着,一个成功建立的连接,必须使得之前网络中残余的数据报都丢失了。,维持这些状态给服务器端带来巨大的负担。 showImg(https://segmentfault.com/img/bV9DQk?w=732&h=563); showImg(https://se...

    LeanCloud 评论0 收藏0
  • 服务器TIME_WAIT和CLOSE_WAIT分析和解决办法

    摘要:服务器出现异常最长出现的状况是服务器保持了大量的状态。此时主动关闭一方必须保持一个有效的状态下维持状态信息,以便可以重发。这就意味着,一个成功建立的连接,必须使得之前网络中残余的数据报都丢失了。,维持这些状态给服务器端带来巨大的负担。 showImg(https://segmentfault.com/img/bV9DQk?w=732&h=563); showImg(https://se...

    helloworldcoding 评论0 收藏0
  • 断开TCP连接

    摘要:我们知道通过三次握手建立可靠连接,通过四次挥手断开连接,连接是比较昂贵的资源。从上分析,安全可靠的断开连接至少需要四次,再多一次的意义不大。连接的异常断开以上都是在理想的情况下发生的,理想状态下,一个连接可以被长期保持。 我们知道TCP通过三次握手建立可靠连接,通过四次挥手断开连接,TCP连接是比较昂贵的资源。为什么TCP需要通过三次握手才能建立可靠的连接?两次不行么?断开连接为什么需...

    fyber 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<