HttpClient4引起的java.net.SocketException: Connection reset解决方法

错误提示如下:

2017-08-24 03:00:04.793  INFO 22781 --- [pool-7-thread-1]o.apache.http.impl.execchain.RetryExec  : I/O exception (java.net.SocketException) caught when processingrequest to {}->http://xx:80: Connection reset

2017-08-24 03:00:04.794  INFO 22781 --- [pool-7-thread-1]o.apache.http.impl.execchain.RetryExec  : Retrying request to {}->http://xx:80

2017-08-24 03:00:04.835  INFO 22781 --- [pool-7-thread-1]o.apache.http.impl.execchain.RetryExec  : I/O exception (java.net.SocketException) caught when processingrequest to {}->http://xx:80: Connection reset

2017-08-24 03:00:04.835  INFO 22781 --- [pool-7-thread-1] o.apache.http.impl.execchain.RetryExec   : Retrying request to{}->http://xx:80

2017-08-24 03:00:04.872  INFO 22781 --- [pool-7-thread-1]o.apache.http.impl.execchain.RetryExec  : I/O exception (java.net.SocketException) caught when processingrequest to {}->http:/xx:80: Connection reset

2017-08-24 03:00:04.872  INFO 22781 --- [pool-7-thread-1]o.apache.http.impl.execchain.RetryExec  : Retrying request to {}->http://xx:80

java.net.SocketException: Connection reset

       at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:118)

       at java.net.SocketOutputStream.write(SocketOutputStream.java:159)

       atorg.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:124)

       atorg.apache.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:136)

       atorg.apache.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:167)

       at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:113)

       atorg.apache.http.entity.mime.content.FileBody.writeTo(FileBody.java:121)

       atorg.apache.http.entity.mime.AbstractMultipartForm.doWriteTo(AbstractMultipartForm.java:134)

       at org.apache.http.entity.mime.AbstractMultipartForm.writeTo(AbstractMultipartForm.java:157)

       atorg.apache.http.entity.mime.MultipartFormEntity.writeTo(MultipartFormEntity.java:113)

       at org.apache.http.impl.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:156)

       atorg.apache.http.impl.conn.CPoolProxy.sendRequestEntity(CPoolProxy.java:162)

       atorg.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:238)

       at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)

       atorg.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)

       atorg.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)

       atorg.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)

       atorg.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)

       atorg.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)

        atorg.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)

       atorg.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)

  使用了网上的处理方法,问题没法解决,使用过的方法列表如下:

1.      使用TCP短链接无效。

 //最后的解决方案是客户端和服务器统一使用TCP短连接
 httppost.setProtocolVersion(HttpVersion.HTTP_1_0);
 httppost.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);

2.      链接时间改再大也无效
        int timeout = 60;//
这个要弄长点
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setSocketTimeout(timeout * 1000)
                .setConnectTimeout(timeout * 1000)
                .setConnectionRequestTimeout(timeout * 1000)
                .build();

3.      下面的方法无效
浏览器发送请求到servletservlet处理时间太久,所以导致chrome浏览器出现ERR_CONNECTION_RESET错误
解决方案: 
在相应servlet执行最后添加一句代码:
Thread.currentThread().join();
表示必须在当前线程执行完之后才返回页面到浏览器。

4.      客户端浏览器刷新,或关闭,就会出现上面的问题,

如果经常出现,就可能是你的系统的性能问题。

网络拥堵的改善也没法解决这种问题

linux服务增加下面的内容
#vi /etc/sysctl.conf
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_keepalive_time=1800
net.ipv4.tcp_max_syn_backlog=4096

5.以为是多线程的问题,结果也不是。

6.以为是pdf文件是加密文件,结果也不是。

到底是什么原因呢。结果是httpClient一直没有处理好的问题,就如异常报的它还是调用了jvm底层

追查代码找到SocketInputStream.socketRead0((FileDescriptor fd, byte b[], int off,int len, int timeout)

意思大概为本地调用方法错误,也就是JVM管理的问题。开发者认为根本不是HttpClient的问题。

但事情还是得想办法解决。我最后还是使用java自带的HttpURLConnection上传数据和附件。

下面的代码来自于网络,但增加解决HttpURLConnection上传文件名乱码的问题。其它的跟网上的例子类似。

 Maven引入:

        <dependency>

            <groupId>net.sf.jmimemagicgroupId>

            <artifactId>jmimemagicartifactId>

            <version>0.1.5version>

        dependency>

代码如下:

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

import java.net.URLEncoder;

import java.nio.ByteBuffer;

import java.nio.CharBuffer;

import java.nio.charset.Charset;

import java.util.List;

import org.apache.http.Consts;

import org.apache.http.util.ByteArrayBuffer;

import com.alibaba.fastjson.JSON;

import net.sf.jmimemagic.Magic;

import net.sf.jmimemagic.MagicMatch;

 

/**

 * Java原生的API可用于发送HTTP请求,即java.net.URLjava.net.URLConnection,这些API很好用、很常用,

 * 但不够简便;

 *

 * 1.通过统一资源定位器(java.net.URL)获取连接器(java.net.URLConnection 2.设置请求的参数 3.发送请求

 * 4.以输入流的形式获取返回内容 5.关闭输入流

 *

 * @author H__D

 *

 */

public classHttpUploadURLConnectionUtils {

 

    public staticfinal Charset UTF8_CHARSET = Consts.UTF_8;

 

    public staticMessageDto snycWebSite(List fileList,TransferWebSiteDto transDto) throws Exception {

       return uploadFile(transDto.getWebSiteUrl(), fileList,transDto);

    }

 

    private staticByteArrayBuffer encode(

           final Charset charset, finalString string) {

       final ByteBuffer encoded = charset.encode(CharBuffer.wrap(string));

       final ByteArrayBuffer bab = newByteArrayBuffer(encoded.remaining());

       bab.append(encoded.array(),encoded.position(), encoded.remaining());

       return bab;

    }

    /**

     * 多文件上传的方法

     *

     * @paramactionUrl:上传的路径

     * @paramuploadFilePaths:需要上传的文件路径,数组

     * @return

     */

    public staticMessageDto uploadFile(String actionUrl,List uploadFilePaths,TransferWebSiteDto transDto) {

       String end = "\r\n";

       String twoHyphens = "--";

       String boundary = "----------------------------123821742118716";

 

       DataOutputStream douts = null;

       InputStream inputStream = null;

       InputStreamReader inputStreamReader =null;

       BufferedReader reader = null;

       StringBuffer resultBuffer = new StringBuffer();

       String tempLine = null;

       HttpURLConnection httpURLConnection =null;

       try {

           // 统一资源

           URL url = newURL(actionUrl);

           // http的连接类

           httpURLConnection =(HttpURLConnection) url.openConnection();

           httpURLConnection.setConnectTimeout(5000); 

           httpURLConnection.setReadTimeout(30000); 

           // 设置是否从httpUrlConnection读入,默认情况下是true;

           httpURLConnection.setDoInput(true);

           // 设置是否向httpUrlConnection输出

           httpURLConnection.setDoOutput(true);

           // Post 请求不能使用缓存

           httpURLConnection.setUseCaches(false);

           // 设定请求的方法,默认是GET

           httpURLConnection.setRequestMethod("POST");

           // 设置字符编码连接参数

           httpURLConnection.setRequestProperty("Connection", "Keep-Alive");

           // 设置字符编码

           httpURLConnection.setRequestProperty("Charset", "UTF-8");

           httpURLConnection.setRequestProperty("Content-Transfer-Encoding", "UTF-8");

           httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0(Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");

           // 设置请求内容类型

           httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

           // 设置DataOutputStream

           douts = newDataOutputStream(httpURLConnection.getOutputStream());

           //input输入框name=data  value=transDto

           StringBuffer strBuf = new StringBuffer();

           strBuf.append(end).append(twoHyphens).append(boundary).append(end); 

           strBuf.append("Content-Disposition: form-data;name=\"data\"\r\n\r\n");

          // StringBody userId = newStringBody(URLEncoder.encode(JSON.toJSONString(transDto), "utf-8"),ContentType.create( "text/plain", Consts.UTF_8));

           strBuf.append(URLEncoder.encode(JSON.toJSONString(transDto), "utf-8"));

           douts.writeBytes(strBuf.toString());

           for (int i = 0; i < uploadFilePaths.size();i++) {

                String filename= uploadFilePaths.get(i).getName();

                MagicMatch match = Magic.getMagicMatch(uploadFilePaths.get(i),false, true); 

                String contentType= match.getMimeType();

                StringBuffer sbinner = newStringBuffer();

                sbinner.append(end).append(twoHyphens).append(boundary).append(end);

                sbinner.append("Content-Disposition: form-data;name=\"file").append(i).append("\";filename=\"").append(filename).append("\"").append(end);

                sbinner.append("Content-Type:" + contentType + "\r\n\r\n"); 

              //解决附件文件名乱码的问题

                ByteArrayBuffer b = encode(UTF8_CHARSET,sbinner.toString());

                douts.write(b.buffer());

                DataInputStream  inStream =new DataInputStream(new FileInputStream(uploadFilePaths.get(i)));

                byte[]buffer = newbyte[1024];

                intlength = 0;

                while((length = inStream.read(buffer)) != -1) {

                    douts.write(buffer, 0, length);

                }

                /*close streams */

                inStream.close();

           }

           douts.writeBytes(end+twoHyphens+ boundary + twoHyphens+ end);

           /* close streams */

           douts.flush();

           douts.close();

           if (httpURLConnection.getResponseCode()>= 300) {

                thrownew Exception(

                        "HTTP Request is not success, Response code is " + httpURLConnection.getResponseCode());

           }

 

            if(httpURLConnection.getResponseCode() ==HttpURLConnection.HTTP_OK) {

                inputStream= httpURLConnection.getInputStream();

                inputStreamReader= new InputStreamReader(inputStream);

                reader= new BufferedReader(inputStreamReader);

                tempLine= null;

                resultBuffer= new StringBuffer();

                while((tempLine = reader.readLine())!= null) {

                    resultBuffer.append(tempLine);

                    resultBuffer.append("\n");

                }

           }

       } catch (Exception e) {

           e.printStackTrace();

       } finally {

           httpURLConnection.disconnect();

       }

       return JSON.parseObject(resultBuffer.toString(), MessageDto.class);

    }

}




你可能感兴趣的:(网络)