Network programming HttpURLConnection实现
我已经读到HttpURLConnection支持持久连接,因此一个连接可以被多个请求重用。我试过了,发送第二封邮件的唯一方法就是再次调用openConnection。否则我会得到一个非法的州例外(“已连接”); 我使用了以下方法:Network programming HttpURLConnection实现,network-programming,java,jdk1.6,httpurlconnection,Network Programming,Java,Jdk1.6,Httpurlconnection,我已经读到HttpURLConnection支持持久连接,因此一个连接可以被多个请求重用。我试过了,发送第二封邮件的唯一方法就是再次调用openConnection。否则我会得到一个非法的州例外(“已连接”); 我使用了以下方法: try{ URL url = new URL("http://someconection.com"); } catch(Exception e){} HttpURLConnection con = (HttpURLConnection) url.openConnect
try{
URL url = new URL("http://someconection.com");
}
catch(Exception e){}
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//set output, input etc
//send POST
//Receive response
//Read whole response
//close input stream
con.disconnect();//have also tested commenting this out
con = (HttpURLConnection) url.openConnection();
//Send new POST
第二个请求是通过相同的TCP连接发送的(用wireshark验证),但我不明白为什么(尽管这是我想要的),因为我调用了disconnect。
我检查了HttpURLConnection的源代码,该实现确实保留了到相同目的地的连接的keepalive缓存。我的问题是,在发送第一个请求后,我看不到如何将连接放回缓存中。断开连接会关闭连接,如果没有断开连接,我仍然看不到连接是如何放回缓存的。我看到缓存有一个run方法可以遍历所有空闲连接(我不确定它是如何调用的),但我找不到如何将连接放回缓存中。唯一可能发生的地方是httpClient的finished方法,但是对于带有响应的POST,不会调用它。
有人能帮我吗
编辑
我的兴趣是,对于tcp连接重用来说,HttpUrlConnection对象的正确处理是什么。输入/输出流是否应该在url.openConnection()后关闭;每次发送新请求时(避免断开连接())?如果是,我在第二次调用url.openConnection()时看不到连接是如何被重用的,因为第一次请求时连接已从缓存中删除,并且找不到它是如何返回的。
是否可能连接没有返回到keepalive缓存(bug?),但操作系统尚未释放tcp连接,并且在新连接上,操作系统返回缓冲连接(尚未释放)或类似的内容?
EDIT2
我找到的唯一亲属是来自
…当应用程序调用close()时
在由返回的InputStream上
URLConnection.getInputStream()中的
JDK的HTTP协议处理程序将尝试
清理连接,如果
成功后,将连接放入
连接缓存供将来重用
HTTP请求
但我不确定这是哪位处理者。sun.net.www.protocol.http.Handler没有像我看到的那样进行任何缓存
谢谢 来自javadoc for HttpURLConnection(我的重点): 每个HttpURLConnection实例都是 用于发出单个请求,但 与服务器的基础网络连接 HTTP服务器可能是透明的 被其他实例共享。调用 InputStream上的close()方法或 HttpURLConnection的OutputStream 请求后可能会释放网络 与此关联的资源 实例,但对任何 共享持久连接。使命感 disconnect()方法可以关闭 如果持久化 否则,该连接处于空闲状态 时间 应该关闭输入/输出流吗 后跟url.openConnection(); 每次都要发送新请求 (避免断开连接()) 对 如果是,我看不出连接是如何进行的 当我打电话的时候 第二个的url.openConnection() 时间,因为连接已断开 第一次从缓存中删除 请求,但找不到它是怎样的 他回来了
您将
HttpURLConnection
与底层Socket
及其底层TCP连接混淆。他们不一样。HttpURLConnection
实例是GC'd,底层的Socket
被池化,除非调用disconnect()。
我发现当InputStream关闭时,连接确实被缓存。一旦inputStream关闭,底层连接将被缓冲。HttpURLConnection对象对于进一步的请求是不可用的,因为该对象仍被视为“已连接”,即其布尔连接被设置为true,并且在将连接放回缓冲区后不会被清除。因此,每次都应该为新的POST实例化一个新的HttpUrlConnection,但是如果底层TCP连接没有超时,它将被重用。
所以EJP答案是正确的描述。尽管显式调用disconnect(),但我看到的行为(重用TCP连接)可能是由于操作系统进行的缓存造成的吗?我不知道。我希望知道的人能解释一下。
谢谢。Hmmh。我可能在这里遗漏了一些东西(因为这是一个老问题),但据我所知,有两种众所周知的方法可以强制关闭底层TCP连接:
- 强制使用HTTP 1.0(1.1引入了持久连接)——这由HTTP请求行指示
- 发送值为“close”的“Connection”标头;这也将迫使关闭
http.maxConnections
指示每个目标在任何给定时间保持活动状态的最大(并发)连接数
因此,通过将java属性
http.keepAlive
设置为false,“强制使用HTTP1.0”可以一次应用于整个应用程序。放弃流将导致TCP连接空闲。应该完全读取响应流。我最初忽略的另一件事,也是在这个主题的大多数答案中被忽略的,就是在异常情况下忘记处理错误流。与此类似的代码修复了我的一个应用程序未正确释放资源的问题:
HttpURLConnection connection = (HttpURLConnection)new URL(uri).openConnection();
InputStream stream = null;
BufferedReader reader = null;
try {
stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
// do work on part of the input stream
} catch (IOException e) {
// read the error stream
InputStream es = connection.getErrorStream();
if (es != null) {
BufferedReader esReader = null;
esReader = new BufferedReader(new InputStreamReader(es, Charset.forName("UTF-8")));
while (esReader.ready() && esReader.readLine() != null) {
}
if (esReader != null)
esReader.close();
}
// do something with the IOException
} finally {
// finish reading the input stream if it was not read completely in the try block, then close
if (reader != null) {
while (reader.readLine() != null) {
}
reader.close();
}
// Not sure if this is necessary, closing the buffered reader may close the input stream?
if (stream != null) {
stream.close();
}
// disconnect
if (connection != null) {
connection.disconnect();
}
}
缓冲读取器并不是绝对必要的,我选择它是因为我的用例需要readi