ClientAbortException Connection reset by peer: socket write error

时间:2024-03-20 11:33:24

最近在整合和上传下载相关的工具类,做了个小demo,如图

 


ClientAbortException Connection reset by peer: socket write error
 

 

 

点击 download链接,程序自动下载使用outputStream write 一个那片海.mp4,这个mp4 大概  44.76MB

 

代码如下:

  

private int					i	= 0;

	@RequestMapping("/download")
	public void download(HttpServletRequest request,HttpServletResponse response) throws IOException{
		i++;
		log.info("access i:{}", i);

		String pathname = null;

		pathname = "D:\\Downloads\\那片海.mp4";
		pathname = "C:\\Users\\feilong\\Downloads\\那片海.mp4";
		//pathname = "D:\\Downloads\\viewfile.png";
		//pathname = "D:\\Downloads\\export-飞天奔月.opml";

		//int contentLength = inputStream.available();

		File file = new File(pathname);
		int contentLength = (int) FileUtil.getFileSize(file);

		// 以流的形式下载文件。
		InputStream inputStream = new FileInputStream(pathname);
		String saveFileName = FileUtil.getFileName(pathname);

		download(saveFileName, inputStream, contentLength, request, response);
	}

 

 

 

普通的IE浏览器下载,不会出现问题但是如果是迅雷下载,或者是 360极速浏览器开了  “使用迅雷下载加速模块”功能

 


ClientAbortException Connection reset by peer: socket write error
 

 

 

 

日志里面瞬间就会出现 10个相同的请求

 

17:59:45 INFO  (DownloadController.java:74) download() - access i:7
17:59:45 INFO  (DownloadController.java:74) download() - access i:8
17:59:45 INFO  (DownloadController.java:74) download() - access i:9
17:59:45 DEBUG (Browser.java:85) <init>() - the user-agent:[Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36]
17:59:45 INFO  (DownloadController.java:74) download() - access i:10
17:59:45 INFO  (DownloadController.java:122) download() - begin download~~,saveFileName:[那片海.mp4],contentLength:[44.76MB]
17:59:45 DEBUG (AbstractHandlerExceptionResolver.java:132) resolveException() - Resolving exception from handler [public void com.feilong.controller.DownloadController.download(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException]: ClientAbortException:  java.net.SocketException: Connection reset by peer: socket write error
17:59:45 DEBUG (AbstractHandlerExceptionResolver.java:132) resolveException() - Resolving exception from handler [public void com.feilong.controller.DownloadController.download(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException]: ClientAbortException:  java.net.SocketException: Software caused connection abort: socket write error
17:59:45 INFO  (DownloadController.java:122) download() - begin download~~,saveFileName:[那片海.mp4],contentLength:[44.76MB]
17:59:45 INFO  (DownloadController.java:122) download() - begin download~~,saveFileName:[那片海.mp4],contentLength:[44.76MB]
17:59:45 INFO  (DownloadController.java:122) download() - begin download~~,saveFileName:[那片海.mp4],contentLength:[44.76MB]
17:59:45 INFO  (DownloadController.java:122) download() - begin download~~,saveFileName:[那片海.mp4],contentLength:[44.76MB]
17:59:45 INFO  (DownloadController.java:74) download() - access i:11

 

 

 

并且 log中会报  异常

  

17:59:45 DEBUG (FrameworkServlet.java:976) processRequest() - Could not complete request
org.apache.catalina.connector.ClientAbortException: null
	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:413) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:359) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:309) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:108) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at com.feilong.commons.core.io.IOWriteUtil.write(IOWriteUtil.java:154) ~[feilong-core-1.0.8-SNAPSHOT.jar:1.0.8-SNAPSHOT]
	at com.feilong.commons.core.io.IOWriteUtil.write(IOWriteUtil.java:97) ~[feilong-core-1.0.8-SNAPSHOT.jar:1.0.8-SNAPSHOT]
	at com.feilong.controller.DownloadController.download(DownloadController.java:147) ~[DownloadController.class:na]
	at com.feilong.controller.DownloadController.download(DownloadController.java:92) ~[DownloadController.class:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_11]

 

 

Caused by: java.net.SocketException: Connection reset by peer: socket write error
	at java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:1.8.0_11]
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) ~[na:1.8.0_11]
	at java.net.SocketOutputStream.write(SocketOutputStream.java:153) ~[na:1.8.0_11]
	at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:366) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.coyote.http11.InternalOutputBuffer$OutputStreamOutputBuffer.doWrite(InternalOutputBuffer.java:240) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.coyote.http11.filters.IdentityOutputFilter.doWrite(IdentityOutputFilter.java:84) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:192) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.coyote.Response.doWrite(Response.java:517) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:408) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
	... 52 common frames omitted

 

 

 究其原因:

 

 

/*
 * 在写数据的时候, 对于 ClientAbortException 之类的异常, 是因为客户端取消了下载,而服务器端继续向浏览器写入数据时, 抛出这个异常,这个是正常的。
 * 尤其是对于迅雷这种吸血的客户端软件, 明明已经有一个线程在读取
 * 如果短时间内没有读取完毕,迅雷会再启第二个、第三个。。。线程来读取相同的字节段,
 * 直到有一个线程读取完毕,迅雷会 KILL掉其他正在下载同一字节段的线程, 强行中止字节读出,造成服务器抛 ClientAbortException。
 */

 

 

这对项目是不小的一笔开销 (从日志中可以看到,每个相同的请求 都会过  Interceptor)

 

 

对于这种异常,我们可以在代码中忽略掉,避免 log太多了代码示例如下:

 

  

try{
			OutputStream outputStream = response.getOutputStream();

			//这种 如果文件一大,很容易内存溢出
			//inputStream.read(buffer);
			//outputStream = new BufferedOutputStream(response.getOutputStream());
			//outputStream.write(buffer);

			IOWriteUtil.write(inputStream, outputStream);
			if (log.isInfoEnabled()){
				Date endDate = new Date();
				log.info(
								"end download,saveFileName:[{}],contentLength:[{}],time use:[{}]",
								saveFileName,
								FileUtil.formatSize(contentLength),
								DateExtensionUtil.getIntervalForView(beginDate, endDate));
			}
		}catch (IOException e){

			//ClientAbortException:  java.net.SocketException: Connection reset by peer: socket write error
			final String exceptionName = e.getClass().getName();

			if (StringUtil.isContain(exceptionName, "ClientAbortException") || StringUtil.isContain(e.getMessage(), "ClientAbortException")){
				log.warn(
								"[ClientAbortException],maybe user use Thunder soft or abort client soft download,exceptionName:[{}],exception message:[{}] ,request User-Agent:[{}]",
								exceptionName,
								e.getMessage(),
								RequestUtil.getHeaderUserAgent(request));
			}else{
				log.error("[download exception],exception name: " + exceptionName, e);
				throw e;
			}
		}

 

 

网站是时候禁用迅雷下载了