Можете ли вы объяснить процесс подключения HttpURLConnection?

Я использую HTTPURLConnection для подключения к веб-службе. Я знаю, как использовать HTTPURLConnection но я хочу понять, как это работает. В принципе, я хочу знать следующее:

  • В какой момент HTTPURLConnection пытается установить соединение с данным URL?
  • На каком этапе я могу узнать, что я смог успешно установить соединение?
  • Установили соединение и отправили фактический запрос, сделанный при вызове на один шаг / метод? Какой метод?
  • Можете ли вы объяснить функцию getOutputStream и getInputStream в непрофессионале? Я замечаю, что когда сервер, к которому я пытаюсь подключиться, не работает, я получаю Exception в getOutputStream . Означает ли это, что HTTPURLConnection начнет устанавливать соединение только при вызове getOutputStream ? Как насчет getInputStream ? Поскольку я могу получить ответ только в getInputStream , значит, я еще не отправил запрос в getOutputStream но просто установил соединение? HttpURLConnection вернется на сервер, чтобы запросить ответ, когда я вызываю getInputStream ?
  • Правильно ли я говорю, что openConnection просто создает новый объект соединения, но пока не устанавливает соединение?
  • Как я могу измерить накладные расходы на чтение и подключить накладные расходы?

 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) { // ... } 

Первые 3 ответа на ваши вопросы перечислены в виде встроенных комментариев, помимо каждого метода, в примере HTTP POST выше.

Из getOutputStream :

Возвращает выходной stream, который записывается в это соединение.

В принципе, я думаю, что у вас есть хорошее представление о том, как это работает, поэтому позвольте мне просто повторить слова непрофессионала. getOutputStream основном открывает stream соединения с целью записи данных на сервер. В приведенном выше примере кода «сообщение» может быть комментарием, который мы отправляем на сервер, который представляет комментарий, оставленный в сообщении. Когда вы видите getOutputStream , вы открываете stream соединения для записи, но на самом деле вы не записываете никаких данных, пока не writer.write("message=" + message); ,

Из getInputStream () :

Возвращает stream ввода, который читается из этого открытого соединения. Исключение SocketTimeoutException может быть выбрано при чтении из возвращаемого входного streamа, если истечет время ожидания чтения до того, как данные будут доступны для чтения.

getInputStream делает обратное. Как и getOutputStream , он также открывает stream соединения , но целью является считывание данных с сервера, а не запись на него. Если соединение или открытие streamа не удастся, вы увидите SocketTimeoutException .

Как насчет getInputStream? Поскольку я могу получить ответ только в getInputStream, значит, я еще не отправил запрос в getOutputStream, но просто установил соединение?

Имейте в виду, что отправка запроса и отправка данных – это две разные операции. Когда вы вызываете getOutputStream или getInputStream url.openConnection() , вы отправляете запрос на сервер для установления соединения. Существует рукопожатие, которое происходит там, где сервер отправляет вам подтверждение, что соединение установлено. Именно в этот момент вы готовы отправить или получить данные. Таким образом, вам не нужно вызывать getOutputStream, чтобы установить соединение, открывающее stream, если только ваша цель для отправки запроса – отправить данные.

С точки зрения непрофессионала, запрос getInputStream эквивалентен телефону, чтобы позвонить в дом вашего друга, чтобы сказать: «Эй, хорошо, если я приеду и возьму эту пару тисков?» и ваш друг устанавливает рукопожатие, говоря: «Конечно, приходите и получите». Затем, в этот момент, соединение сделано, вы идете в дом вашего друга, стучите в дверь, просите тиски и возвращаетесь в свой дом.

Используя аналогичный пример для getOutputStream должны позвонить своему другу и сказать: «Эй, у меня есть те деньги, которые я должен вам, могу ли я отправить их вам»? Твой друг, нуждающийся в деньгах и больных, которые ты так долго хранил, говорит: «Конечно, перейди к тебе, дешевый ублюдок». Итак, вы ходите в дом вашего друга и отправляете ему деньги. Затем он вышвырнет вас, и вы вернетесь в свой дом.

Теперь, продолжая пример непрофессионала, давайте посмотрим на некоторые Исключения. Если вы позвонили своему другу и его не было дома, это может быть ошибка 500. Если вы позвонили и получили сообщение с отключенным номером, потому что ваш друг устал от того, что вы все время заимствуете деньги, это 404 страница не найдена. Если ваш телефон мертв, потому что вы не оплатили счет, это может быть исключение IOException. (ПРИМЕЧАНИЕ. Этот раздел может быть не на 100% правильным. Он призван дать вам общее представление о том, что происходит в условиях непрофессионала.)

Вопрос № 5:

Да, вы правы, что openConnection просто создает новый объект подключения, но не устанавливает его. Соединение устанавливается при вызове getInputStream или getOutputStream.

openConnection создает новый объект подключения. Из URL.openConnection javadocs :

Новое соединение открывается каждый раз, вызывая метод openConnection обработчика протокола для этого URL-адреса.

Соединение устанавливается при вызове 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) ); 

Я уверен, что существуют более сложные методы измерения времени запроса и накладных расходов, но этого, как правило, достаточно для моих нужд.

Сведения о закрытии соединений, о которых вы не спрашивали, см. В разделе « Java», когда соединение URL закрывается? ,

Тим Брей представил краткий шаг за шагом, заявив, что openConnection () не устанавливает фактическое соединение. Скорее, фактическое HTTP-соединение не установлено до тех пор, пока вы не вызовете методы, такие как getInputStream () или getOutputStream ().

http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection

В какой момент HTTPURLConnection пытается установить соединение с данным URL?

В порту, указанном в URL-адресе, если есть, в противном случае 80 для HTTP и 443 для HTTPS. Я считаю, что это документировано.

На каком этапе я могу узнать, что я смог успешно установить соединение?

Когда вы вызываете getInputStream () или getOutputStream () или getResponseCode () без получения исключения.

Установили соединение и отправили фактический запрос, сделанный при вызове на один шаг / метод? Какой метод?

Нет, нет.

Можете ли вы объяснить функцию getOutputStream и getInputStream в непрофессионале?

Любой из них сначала подключается, если необходимо, а затем возвращает требуемый stream.

Я замечаю, что когда сервер, к которому я пытаюсь подключиться, не работает, я получаю исключение в getOutputStream. Означает ли это, что HTTPURLConnection начнет устанавливать соединение только при вызове getOutputStream? Как насчет getInputStream? Поскольку я могу получить ответ только в getInputStream, значит, я еще не отправил запрос в getOutputStream, но просто установил соединение? HttpURLConnection вернется на сервер, чтобы запросить ответ, когда я вызываю getInputStream?

См. Выше.

Правильно ли я говорю, что openConnection просто создает новый объект соединения, но пока не устанавливает соединение?

Да.

Как я могу измерить накладные расходы на чтение и подключить накладные расходы?

Connect: возьмите время getInoutStream () или getOutputStream (), чтобы вернуться, в зависимости от того, что вы назовете первым. Читайте: время от начала первого чтения до получения EOS.

В какой момент HTTPURLConnection пытается установить соединение с данным URL?

Стоит уточнить, есть экземпляр «UrlConnection», а затем есть базовое соединение сокетов Tcp / Ip / SSL , 2 разных понятия. Экземпляр «UrlConnection» или «HttpUrlConnection» является синонимом одного запроса на HTTP-страницу и создается при вызове url.openConnection (). Но если вы делаете несколько url.openConnection () из экземпляра «url», то, если вам повезет, они будут повторно использовать один и тот же сокет Tcp / Ip и файлы для связи SSL … это хорошо, если вы делая много запросов страниц на один и тот же сервер, особенно хорошо, если вы используете SSL, где накладные расходы на установку сокета очень высоки.

См .: реализация HttpURLConnection

Давайте будем гением компьютера.