我使用HTTPURLConnection
连接到网络服务。我知道如何使用HTTPURLConnection
,但我想了解它是如何工作的。基本上,我想知道以下内容:
HTTPURLConnection
尝试建立与给定网址的连接在哪一点?getOutputStream
和getInputStream
的功能吗?我注意到,当我尝试连接的服务器关闭时,我会在Exception
获得getOutputStream
。这是否意味着HTTPURLConnection
仅在我调用getOutputStream
时才开始建立连接? getInputStream
怎么样?由于我只能在getInputStream
获得响应,那么这是否意味着我还没有在getOutputStream
发送任何请求,而只是建立连接?当我调用HttpURLConnection
时,getInputStream
会回到服务器请求响应吗?openConnection
只创建一个新的连接对象但尚未建立任何连接?答案 0 :(得分:176)
String message = URLEncoder.encode("my message", "UTF-8");
try {
// instantiate the URL object with the target URL of the resource to
// request
URL url = new URL("http://www.example.com/comment");
// instantiate the HttpURLConnection with the URL object - A new
// connection is opened every time by calling the openConnection
// method of the protocol handler for this URL.
// 1. This is the point where the connection is opened.
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// set connection output to true
connection.setDoOutput(true);
// instead of a GET, we're going to send using method="POST"
connection.setRequestMethod("POST");
// instantiate OutputStreamWriter using the output stream, returned
// from getOutputStream, that writes to this connection.
// 2. This is the point where you'll know if the connection was
// successfully established. If an I/O error occurs while creating
// the output stream, you'll see an IOException.
OutputStreamWriter writer = new OutputStreamWriter(
connection.getOutputStream());
// write data to the connection. This is data that you are sending
// to the server
// 3. No. Sending the data is conducted here. We established the
// connection with getOutputStream
writer.write("message=" + message);
// Closes this output stream and releases any system resources
// associated with this stream. At this point, we've sent all the
// data. Only the outputStream is closed at this point, not the
// actual connection
writer.close();
// if there is a response code AND that response code is 200 OK, do
// stuff in the first if block
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// OK
// otherwise, if any other status code is returned, or no status
// code is returned, do stuff in the else block
} else {
// Server returned HTTP error code.
}
} catch (MalformedURLException e) {
// ...
} catch (IOException e) {
// ...
}
在上面的示例HTTP POST中,您的问题的前3个答案在每个方法旁边列为内联注释。
返回写入此连接的输出流。
基本上,我认为你对这是如何运作有很好的理解,所以让我以外行的方式重申一下。 getOutputStream
基本上打开连接流,目的是将数据写入服务器。在上面的代码示例中,“message”可以是我们发送到服务器的注释,该注释表示帖子上留下的评论。当您看到getOutputStream
时,您正在打开连接流进行写入,但在致电writer.write("message=" + message);
之前,您实际上并未写入任何数据。
返回从此打开的连接读取的输入流。如果读取超时在数据可用于读取之前到期,则从返回的输入流读取时可能抛出SocketTimeoutException。
getInputStream
反其道而行之。与getOutputStream
一样,它也会打开连接流,但目的是从服务器读取数据,而不是写入数据。如果连接或流打开失败,您会看到SocketTimeoutException
。
getInputStream怎么样?因为我只能在getInputStream上获得响应,那么这是否意味着我还没有在getOutputStream发送任何请求,而只是建立连接?
请记住,发送请求和发送数据是两种不同的操作。当您调用 getOutputStream或getInputStream url.openConnection()
时,您向服务器发送请求以建立连接。发生握手,服务器向您发回确认连接已建立的确认。然后,在那个时间点,您准备发送或接收数据。因此,您不需要调用getOutputStream来建立连接打开一个流,除非您发出请求的目的是发送数据。
通俗地说,提出getInputStream
请求相当于打电话给你朋友的房子说“嘿,如果我过来借那副副把手,还可以吗?”和你的朋友说:“当然!来吧,得到它”。然后,在那时,连接完成,你走到朋友的家里,敲门,请副把手,然后走回你家。
使用getOutputStream
的类似示例会涉及给你的朋友打电话并说“嘿,我有欠你的钱,我可以寄给你吗”?你的朋友,你需要金钱和生病才能保存这么长时间,他说:“当然,请你过来这个便宜的私生子”。所以你走到你朋友的家里并把钱“邮寄”给他。然后他把你踢出去然后走回你家。
现在,继续这个外行的例子,让我们看看一些例外情况。如果你打电话给你的朋友并且他不在家,那可能是500错误。如果您打电话并收到断开连接的号码信息,因为您的朋友已经厌倦了您一直借钱,那就是找不到404页面。如果您的手机因为没有支付账单而死亡,那可能是IOException。 (注意:此部分可能不是100%正确。它旨在让您大致了解外行人所发生的事情。)
问题#5:
是的,你是正确的,openConnection只是创建一个新的连接对象,但没有建立它。当您调用getInputStream或getOutputStream时建立连接。
openConnection
创建一个新的连接对象。来自URL.openConnection javadocs:
每次通过调用此URL的协议处理程序的openConnection方法打开一个新连接。
当您调用openConnection时建立连接,并在实例化时调用InputStream,OutputStream或两者。
问题#6 :
为了测量开销,我通常会在整个连接块周围包含一些非常简单的时序代码,如下所示:
long start = System.currentTimeMillis();
log.info("Time so far = " + new Long(System.currentTimeMillis() - start) );
// run the above example code here
log.info("Total time to send/receive data = " + new Long(System.currentTimeMillis() - start) );
我确信有更多高级方法可以测量请求时间和开销,但这通常足以满足我的需求。
有关关闭连接的信息,请参阅In Java when does a URL connection close?。
答案 1 :(得分:14)
Tim Bray一步一步地说明了openConnection()没有建立实际的连接。相反,在调用getInputStream()或getOutputStream()等方法之前,不会建立实际的HTTP连接。
http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection
答案 2 :(得分:1)
HTTPURLConnection在哪一点尝试建立与给定URL的连接?
在URL中指定的端口(如果有),否则为80表示HTTP,443表示HTTPS。我相信这是记录在案的。
我可以在哪一点知道我能够成功建立连接?
调用getInputStream()或getOutputStream()或getResponseCode()而不会出现异常。
是否建立连接并在一步/方法调用中发送实际请求?它是什么方法?
不,没有。
你能解释一下外行人的getOutputStream和getInputStream的功能吗?
如果需要,它们中的任何一个首先连接,然后返回所需的流。
我注意到当我尝试连接的服务器关闭时,我在getOutputStream上得到一个Exception。这是否意味着HTTPURLConnection只会在调用getOutputStream时开始建立连接? getInputStream怎么样?因为我只能在getInputStream中获得响应,那么它是否意味着我还没有在getOutputStream发送任何请求但只是建立连接?当我调用getInputStream时,HttpURLConnection是否返回服务器请求响应?
见上文。
我是否正确地说openConnection只是创建一个新的连接对象但是还没有建立任何连接?
是
如何衡量读取开销和连接开销?
连接:花时间getInoutStream()或getOutputStream()返回,无论你先调用哪一个。阅读:从开始第一次阅读到获得EOS的时间。
答案 3 :(得分:1)
我通过练习捕获了低级别的数据包交换,发现网络连接仅由诸如getInputStream,getOutputStream,getResponseCode,getResponseMessage等操作触发。
这是我尝试编写一个小程序以将文件上传到Dropbox时捕获的数据包交换。
下面是我的玩具程序和注释
/* Create a connection LOCAL object,
* the openConnection() function DOES NOT initiate
* any packet exchange with the remote server.
*
* The configurations only setup the LOCAL
* connection object properties.
*/
HttpURLConnection connection = (HttpURLConnection) dst.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
...//headers setup
byte[] testContent = {0x32, 0x32};
/**
* This triggers packet exchange with the remote
* server to create a link. But writing/flushing
* to a output stream does not send out any data.
*
* Payload are buffered locally.
*/
try (BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream())) {
outputStream.write(testContent);
outputStream.flush();
}
/**
* Trigger payload sending to the server.
* Client get ALL responses (including response code,
* message, and content payload)
*/
int responseCode = connection.getResponseCode();
System.out.println(responseCode);
/* Here no further exchange happens with remote server, since
* the input stream content has already been buffered
* in previous step
*/
try (InputStream is = connection.getInputStream()) {
Scanner scanner = new Scanner(is);
StringBuilder stringBuilder = new StringBuilder();
while (scanner.hasNextLine()) {
stringBuilder.append(scanner.nextLine()).append(System.lineSeparator());
}
}
/**
* Trigger the disconnection from the server.
*/
String responsemsg = connection.getResponseMessage();
System.out.println(responsemsg);
connection.disconnect();
答案 4 :(得分:0)
HTTPURLConnection在哪一点尝试建立与给定URL的连接?
值得澄清的是,有'UrlConnection'实例,然后是基础 Tcp / Ip / SSL套接字连接,2个不同的概念。 “UrlConnection”或“HttpUrlConnection”实例与单个HTTP页面请求同义,并在您调用url.openConnection()时创建。但是如果你从一个'url'实例做多个url.openConnection(),那么如果你很幸运,他们会重复使用相同的Tcp / Ip套接字和SSL握手的东西......如果你是好的话对同一台服务器进行大量的页面请求,尤其是如果你使用SSL,建立套接字的开销非常高。