java.net.SocketException:使用 HTTPConnection 重置连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27242426/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java.net.SocketException: Connection reset With HTTPConnection
提问by Hitesh Kumar
I am trying to hit some external API to fetch some data. When the data size is small, everything works fine but when the size of data returned by the API is big I get CONNECTION RESETexception. The below code is from java class InterfaceHelper and I have also marked the comment at the line no where I am getting exception [Its while trying to read data from InputStream].
我试图点击一些外部 API 来获取一些数据。当数据量很小时,一切正常,但是当 API 返回的数据量很大时,我会收到CONNECTION RESET异常。下面的代码来自 java 类 InterfaceHelper,我还在我遇到异常的行 no 处标记了注释 [它在尝试从 InputStream 读取数据时]。
I have tried to search so many question on STACKOVERFLOW itself but didn't find an appropriate answer. So please don't mark it as duplicate question. I want to know what is the reason behind this problem, and what is the proper solution for this problem. If you find this question as duplicate please answer it before marking it as duplicate. I dare you.
我试图在 STACKOVERFLOW 本身上搜索这么多问题,但没有找到合适的答案。所以请不要将其标记为重复问题。我想知道这个问题背后的原因是什么,这个问题的正确解决方案是什么。如果您发现此问题重复,请在将其标记为重复之前回答。我赌你。
Find below my code which I have used. URL is some dummy url as for security reason I cannot mention the actual URL I have used.
在下面找到我使用过的代码。URL 是一些虚拟 URL,出于安全原因,我无法提及我使用的实际 URL。
try{
URL url = new URL("http://example.com/someParams/SOME-ACCESS-TOKEN");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Language", "en-US");
connection.setRequestProperty("X-EXAMPLE-LOGIN", "XXXXXXXX");
connection.setRequestProperty("X-EXAMPLE-PASSWORD", "XXXXXX");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
DataInputStream input = new DataInputStream(connection.getInputStream());
String ret = "";
if(input!=null){
for( int c = input.read(); c != -1; c = input.read() ) { //InterfaceHelper.java:695
ret = ret + String.valueOf((char)c);
}
}
if(input!=null)
input.close();
if(connection!=null)
connection.disconnect();
if(ret!=null && ret.length()>0){
return ret;
}
}catch(Exception e) {
e.printStackTrace();
}
This the exception I get
这是我得到的例外
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:196)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:442)
at sun.security.ssl.InputRecord.readV3Record(InputRecord.java:554)
at sun.security.ssl.InputRecord.read(InputRecord.java:509)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:884)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
at sun.net.www.http.ChunkedInputStream.fastRead(ChunkedInputStream.java:244)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:689)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3053)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3047)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3035)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at com.lsa.akosha.util.InterfaceHelper.hitApiBrandWatch(InterfaceHelper.java:695)
at com.lsa.akosha.service.brand.BrandCronService.brandSentiments(BrandCronService.java:288)
at com.lsa.akosha.util.thread.BrandWatchCronConverse.executeInternal(BrandWatchCronConverse.java:60)
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557)
采纳答案by Hitesh Kumar
I tried to debug it again and again, this time while debugging I found that reading data from DataInputStream is the culprit here.
我一次又一次地调试它,这次在调试时我发现从 DataInputStream 读取数据是这里的罪魁祸首。
The line dataInputStream.read() reads one char at a time, and I have to convert it into String. Below is the code
行 dataInputStream.read() 一次读取一个字符,我必须将其转换为字符串。下面是代码
String ret = "";
if(input!=null){
for( int c = input.read(); c != -1; c = input.read() ) { //InterfaceHelper.java:695
ret = ret + String.valueOf((char)c);
}
}
The main problem is that I am reading data into int and then convert it into char and then into String i.e. ret = ret + String.valueOf((char)c);.
主要问题是我正在将数据读入 int 然后将其转换为 char 然后转换为 String 即ret = ret + String.valueOf((char)c); .
Now I have removed the DataInputStream and used BufferInputStream and used bufferInputStream.readLine() which directly read's line in string from InputStream, so no type casting which saves lots of time in reading data from stream and hence till the time connection and stream expires it reads the data and then I close both.
现在我已经删除了 DataInputStream 并使用了 BufferInputStream 并使用了 bufferInputStream.readLine() 它直接从 InputStream 读取字符串中的行,因此没有类型转换可以节省大量时间从流读取数据,因此直到时间连接和流到期它读取数据,然后我关闭两者。
This way my problem is resolved. I am posting my new code which helps me in solving my problem.
这样我的问题就解决了。我正在发布我的新代码,这有助于我解决我的问题。
try{
URL url = new URL("http://example.com/someParams/SOME-ACCESS-TOKEN");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Language", "en-US");
connection.setRequestProperty("X-EXAMPLE-LOGIN", "XXXXXXXX");
connection.setRequestProperty("X-EXAMPLE-PASSWORD", "XXXXXX");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setConnectTimeout(99999999);
connection.setReadTimeout(99999999);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//DataInputStream input = new DataInputStream(connection.getInputStream());
String ret = "";
/* if(in!=null){
for( int c = input.read(); c != -1; c = input.read() ) {
ret = ret + String.valueOf((char)c);
if(input==null || connection==null)
break;
}
}*/
String inputLine;
while ((inputLine = in.readLine()) != null)
{
ret = ret + inputLine;
}
if(in!=null)
in.close();
if(connection!=null)
connection.disconnect();
if(ret!=null && ret.length()>0){
return ret;
}
}catch(Exception e) {
e.printStackTrace();
}
回答by Mark Bramnik
maybe its just quirks, but I've found some "weird" things in your post.
也许它只是怪癖,但我在你的帖子中发现了一些“奇怪”的东西。
- You use SSL connection (as it appears in the stacktrace) but in the provided example this is no HTTPS at all.
- application/x-www-form-urlencoded header is usually used with POST requests. Full explanation on this read here
- 您使用 SSL 连接(如堆栈跟踪中所示),但在提供的示例中,这根本不是 HTTPS。
- application/x-www-form-urlencoded 标头通常与 POST 请求一起使用。在这个充分说明阅读这里
I'm just saying that this can be misleading to some extent.
我只是说这在某种程度上可能会产生误导。
Now regarding the question itself.
现在关于问题本身。
All-in-all - connection reset means that for some reason the connection between the client and the server is broken. For example, the server decides to close the connection. The debugging process can be really tricky here, so if I were you, I would have tried a couple of techniques, depending on environment you're working on:
总而言之 - 连接重置意味着由于某种原因客户端和服务器之间的连接中断。例如,服务器决定关闭连接。调试过程在这里可能非常棘手,因此如果我是您,我会尝试几种技术,具体取决于您正在使用的环境:
Remove SSL and work with plain HTTP. This way you can put a proxy in-between and analyze the network traffic better. Stuff like Burpcan help here.
Try to eliminate the possibility that some firewall/proxy/whatever just dumps the connection for its own reasons. Maybe it worth to run this code in the same machine with the server (of course if its a viable option) just for the sake of testing how this works with "localhost", you know.
I'm not really familiar with this fairly low level API and know all its quirks. But maybe you can use HttpClient instead, this way you'll probably eliminate the need to know all the "low-level" flags, maybe its something wrong there.
删除 SSL 并使用纯 HTTP。通过这种方式,您可以在中间放置一个代理并更好地分析网络流量。Burp 之类的东西可以在这里提供帮助。
尝试消除某些防火墙/代理/任何出于自身原因转储连接的可能性。也许值得在与服务器的同一台机器上运行此代码(当然,如果它是一个可行的选择)只是为了测试它如何与“localhost”一起工作,你知道。
我不是很熟悉这个相当低级的 API 并且知道它的所有怪癖。但是也许您可以改用 HttpClient ,这样您可能就不需要知道所有“低级”标志,也许那里有问题。
Hope this helps
希望这可以帮助
回答by Dhruv Raj Singh
connection.setRequestMethod("GET");
connection.setRequestMethod("GET");
Instead get method try using
而是 get 方法尝试使用
connection.setRequestMethod("POST");
connection.setRequestMethod("POST");
because get method has limit to send the data.
因为 get 方法有发送数据的限制。
回答by user207421
This is clearly not the real code, as noted in my comment above, but
正如我在上面的评论中所指出的,这显然不是真正的代码,但是
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
connection.setDoOutput(true);
You aren't sending any output so you shouldn't be calling these methods at all. And setDoOutput(true)
contradicts setRequestMethod("GET");
.
您没有发送任何输出,因此您根本不应该调用这些方法。并且setDoOutput(true)
自相矛盾setRequestMethod("GET");
。
Alternatively, sendsome output.
或者,发送一些输出。