HttpClient连接由peer重置:套接字写入错误

时间:2016-01-08 09:19:39

标签: java apache httpclient

我使用httpclient 4.4发送get和post请求。我刚刚创建了一个简单的httpclient包装器,以便于使用:


    package com.u8.server.sdk;

    import com.sun.net.httpserver.Headers;
    import com.u8.server.log.Log;
    import org.apache.http.Header;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.HttpRequestRetryHandler;
    import org.apache.http.client.ResponseHandler;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.socket.PlainConnectionSocketFactory;
    import org.apache.http.conn.ssl.NoopHostnameVerifier;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.apache.http.entity.ByteArrayEntity;
    import org.apache.http.impl.client.BasicCookieStore;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.impl.cookie.BasicClientCookie;
    import org.apache.http.message.BasicHeader;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.protocol.HttpContext;
    import org.apache.http.ssl.SSLContextBuilder;
    import org.apache.http.util.EntityUtils;
    import org.springframework.util.StringUtils;

    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.CookiePolicy;
    import java.net.URLEncoder;
    import java.nio.charset.Charset;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    /**
     * Created by ant on 2015/10/12.
     */
    public class UHttpAgent {

        private int connectTimeout = 5000;  //5s
        private int socketTimeout = 5000;   //5s
        private int maxTotalConnections = 200; 

        private static UHttpAgent instance;

        private CloseableHttpClient httpClient;

        private UHttpAgent(){

        }

        public static UHttpAgent getInstance(){
            if(instance == null){
                instance = new UHttpAgent();

            }
            return instance;
        }

        public static UHttpAgent newInstance(){
            return new UHttpAgent();
        }


        public String get(String url, Map params){

            return get(url, null, params, "UTF-8");
        }


        public String post(String url, Map params){

            return post(url, null, params, "UTF-8");
        }


        public String get(String url , Map headers, Map params, String encoding){

            if(this.httpClient == null){
                init();
            }

            String fullUrl = url;
            String urlParams = parseGetParams(params, encoding);

            if (urlParams != null)
            {
                if (url.contains("?"))
                {
                    fullUrl = url + "&" + urlParams;
                }
                else
                {
                    fullUrl = url + "?" + urlParams;
                }
            }

            Log.d("the full url is "+ fullUrl);
            HttpGet getReq = new HttpGet(fullUrl.trim());
            getReq.setHeaders(parseHeaders(headers));
            ResponseHandler responseHandler = new ResponseHandler() {
                @Override
                public String handleResponse(HttpResponse httpResponse) throws IOException {
                    HttpEntity entity = httpResponse.getEntity();
                    return entity != null ? EntityUtils.toString(entity) : null;
                }
            };

            try {

                String res = httpClient.execute(getReq, responseHandler);

                return res;

            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                getReq.releaseConnection();
            }

            return null;
        }


        public String post(String url, Map headers, Map params, String encoding){

            List pairs = new ArrayList();
            if(params != null){

                for(String key : params.keySet()){
                    pairs.add(new BasicNameValuePair(key, params.get(key)));
                }
            }

            return post(url, headers, new UrlEncodedFormEntity(pairs, Charset.forName(encoding)));
        }


        public String post(String url, Map headers, HttpEntity entity){

            if(this.httpClient == null) {
                init();
            }

            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeaders(parseHeaders(headers));
            httpPost.setEntity(entity);

            ResponseHandler responseHandler = new ResponseHandler() {
                @Override
                public String handleResponse(HttpResponse httpResponse) throws IOException {
                    HttpEntity entity = httpResponse.getEntity();
                    return entity != null ? EntityUtils.toString(entity) : null;
                }
            };

            try {


                String body = httpClient.execute(httpPost, responseHandler);

                return body;

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                httpPost.releaseConnection();
            }

            return null;

        }


        private Header[] parseHeaders(Map headers){
            if(null == headers || headers.isEmpty()){
                return getDefaultHeaders();
            }

            Header[] hs = new BasicHeader[headers.size()];
            int i = 0;
            for(String key : headers.keySet()){
                hs[i] = new BasicHeader(key, headers.get(key));
                i++;
            }

            return hs;
        }


        private Header[] getDefaultHeaders(){
            Header[] hs = new BasicHeader[2];
            hs[0] = new BasicHeader("Content-Type", "application/x-www-form-urlencoded");
            hs[1] = new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");
            return hs;
        }


        private String parseGetParams(Map data, String encoding){
            if(data == null || data.size()  keyItor = data.keySet().iterator();
            while(keyItor.hasNext()){
                String key = keyItor.next();
                String val = data.get(key);

                try {
                    result.append(key).append("=").append(URLEncoder.encode(val, encoding).replace("+", "%2B")).append("&");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }

            return result.deleteCharAt(result.length() - 1).toString();

        }


        private void init(){

            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(connectTimeout)
                    .setSocketTimeout(socketTimeout)
                    .setExpectContinueEnabled(true)
                    .setAuthenticationEnabled(true)
                    .build();

            HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
                @Override
                public boolean retryRequest(IOException e, int retryNum, HttpContext httpContext) {

                    if(retryNum >= 3){
                        return false;
                    }


                    if(e instanceof org.apache.http.NoHttpResponseException
                            || e instanceof org.apache.http.client.ClientProtocolException
                            || e instanceof java.net.SocketException){

                        return true;
                    }

                    return false;
                }
            };


            try{

                SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return true;
                    }
                }).build();

                HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
                SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);

                Registry socketFactoryRegistry = RegistryBuilder.create()
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .register("https", sslFactory)
                        .build();

                PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
                connMgr.setMaxTotal(maxTotalConnections);
                connMgr.setDefaultMaxPerRoute((connMgr.getMaxTotal()));

                HttpClientBuilder builder = HttpClients.custom()
                        .setDefaultRequestConfig(requestConfig)
                        .setSslcontext(sslContext)
                        .setConnectionManager(connMgr)
                        .setRetryHandler(retryHandler);

                this.httpClient = builder.build();


            }catch (Exception e){
                e.printStackTrace();
            }

        }

        public HttpClient getHttpClient(){

            return this.httpClient;
        }

        public void destroy(){

            if(this.httpClient != null){
                try{
                    this.httpClient.close();
                    this.httpClient = null;
                }catch (Exception e){
                    e.printStackTrace();
                }

            }
        }


    }

当我使用此类发送帖子请求时。发生了一件奇怪的事情:

第一次,我向服务器发送了一个帖子请求,没关系 几分钟后,我向服务器发送了相同的请求,也没问题。 但几分钟后,我发出了同样的请求,出了点问题:


    java.net.SocketException: Connection reset by peer: socket write error
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
        at org.apache.http.impl.conn.LoggingOutputStream.write(LoggingOutputStream.java:77)
        at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:126)
        at org.apache.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:138)
        at org.apache.http.impl.io.SessionOutputBufferImpl.flush(SessionOutputBufferImpl.java:146)
        at org.apache.http.impl.BHttpConnectionBase.doFlush(BHttpConnectionBase.java:175)
        at org.apache.http.impl.DefaultBHttpClientConnection.flush(DefaultBHttpClientConnection.java:185)
        at org.apache.http.impl.conn.CPoolProxy.flush(CPoolProxy.java:177)
        at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:215)
        at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:122)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:220)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:164)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:139)
        at com.u8.server.sdk.UHttpAgent.post(UHttpAgent.java:259)
        at com.u8.server.sdk.UHttpAgent.post(UHttpAgent.java:147)
        at com.u8.server.sdk.baidu.BaiduSDK.verify(BaiduSDK.java:30)
        at com.u8.server.web.UserAction.getLoginToken(UserAction.java:100)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)

但是,我仍然向服务器发送相同的请求,再次没问题。

每次按照上述步骤尝试时,都会发生同样的事情。

任何人都可以帮助我吗?非常感谢。

1 个答案:

答案 0 :(得分:0)

客户端的对等方是服务器。因此“通过对等方重置连接”表示服务器重置套接字。重置意味着强制关闭。

这可能是因为服务器中存在错误。如果您还编写了服务器或servlet(如自定义协议的情况),则需要检查服务器的行为以检查其原因。服务器的日志文件可能提供线索。

如果服务器具有防止双重行为或恶意客户端的保护,则服务器可能已重置套接字,因为它已将您的客户端归类为行为不端。如果您实现了客户端协议代码,则可能是因为协议实现中存在错误。如果您使用第三方代码处理通信协议,您可能仍会滥用它;例如,通过发送过大的请求。 HTTP服务器通过对头字段和主体强加最大长度来保护自己免受拒绝服务攻击,并要求客户端以相当快的速率发送数据(不会长时间暂停),这种情况并不少见。您的客户可能已经违反了这些保护措施。