Czy możesz wyjaśnić proces połączenia HttpURLConnection?

Używam HTTPURLConnection, aby połączyć się z usługą internetową. Wiem, jak używać HTTPURLConnection, ale chcę zrozumieć, jak to działa. W zasadzie chcę wiedzieć, co następuje:

  • w którym punkcie HTTPURLConnection próbuje nawiązać połączenie z podanym adresem URL?
  • w którym momencie mogę wiedzieć, że udało mi się pomyślnie nawiązać połączenie?
  • czy nawiązanie połączenia i wysłanie rzeczywistego żądania odbywa się w jednym wywołaniu krok / metoda? Jaka to metoda?
  • czy możesz wyjaśnić Funkcja getOutputStream i getInputStream w pojęciu laika? Zauważyłem, że gdy serwer, z którym próbuję się połączyć, jest wyłączony, dostaję Exception na getOutputStream. Czy to znaczy, że HTTPURLConnection zacznie nawiązywać połączenie dopiero po wywołaniu getOutputStream? A może getInputStream? Ponieważ mogę uzyskać odpowiedź tylko na getInputStream, to czy to znaczy, że nie wysłałem jeszcze żadnego żądania na getOutputStream, ale po prostu nawiązałem połączenie? Czy HttpURLConnection wrócić do serwera, aby poprosić o odpowiedź, gdy wywołuję getInputStream?
  • Czy mam rację powiedzieć, że openConnection po prostu tworzy nowy obiekt connection, ale nie ustanawia jeszcze żadnego połączenia?
  • Jak mogę zmierzyć nadmiarowość odczytu i podłączyć nadmiarowość?
Author: Arci, 2012-04-12

4 answers

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

Pierwsze 3 odpowiedzi na twoje pytania są wymienione jako komentarze inline, obok każdej metody, w przykładzie HTTP POST powyżej.

From getOutputStream :

Zwraca strumień wyjściowy, który zapisuje do tego połączenia.

Zasadniczo, myślę, że masz dobre zrozumienie, jak to działa, więc pozwól, że powtórzę w kategoriach laika. getOutputStream w zasadzie otwiera połączenie strumień, z zamiarem zapisu danych do serwer. W powyższym przykładzie kodu "wiadomość" może być komentarzem, który wysyłamy na serwer, który reprezentuje komentarz pozostawiony na poście. Kiedy widzisz getOutputStream, otwierasz połączenie stream do zapisu, ale nie zapisujesz żadnych danych, dopóki nie zadzwonisz writer.write("message=" + message);.

From getInputStream():

Zwraca strumień wejściowy, który odczytuje to otwarte połączenie. SocketTimeoutException może być wyrzucony podczas odczytu ze zwracanego strumienia wejściowego, jeśli limit czasu odczytu wygasa przed udostępnieniem danych do odczytu.

getInputStream robi odwrotnie. Podobnie jak getOutputStream, otwiera również strumień połączenia , ale intencją jest odczytywanie danych z serwera, a nie zapisywanie do niego. Jeśli połączenie lub otwarcie strumienia nie powiedzie się, zobaczysz SocketTimeoutException.

A może getInputStream? Ponieważ jestem w stanie uzyskać odpowiedź tylko w getInputStream, to znaczy, że nie wysłałem jeszcze żadnego żądania w getOutputStream, ale po prostu ustanawia połączenie?

Należy pamiętać, że wysyłanie żądania i wysyłanie danych to dwie różne operacje. Gdy wywołujesz getOutputStream lub getInputStream url.openConnection(), wysyłasz żądanie do serwera w celu nawiązania połączenia. Istnieje uścisk dłoni, który ma miejsce, gdy serwer wysyła Ci potwierdzenie, że połączenie zostało nawiązane. W tym momencie jesteś gotowy do wysyłania lub odbierania danych. Dlatego nie musisz wywoływać getOutputStream do nawiąż połączenie otwórz strumień, chyba że twoim celem jest wysłanie danych.

W kategoriach laika, złożenie getInputStream prośba jest równoznaczne z wykonaniem telefonu do domu twojego przyjaciela, aby powiedzieć "Hej, mogę przyjść i pożyczyć parę uchwytów?"a twój przyjaciel ustanawia uścisk dłoni mówiąc:" jasne! Chodź i weź to". Potem, w tym momencie, połączenie jest nawiązane, idziesz do domu przyjaciela, pukasz do drzwi, prosisz o występek chwyty i wróć do domu.

Użycie podobnego przykładu dla getOutputStream wiązałoby się z telefonem do przyjaciela i powiedzeniem "Hej, mam te pieniądze, które jestem ci winien, mogę ci je wysłać"? Twój przyjaciel, potrzebujący pieniędzy i chory w środku, że trzymałeś je tak długo, mówi "jasne, chodź tu ty tani draniu". Więc idziesz do domu przyjaciela i "wysyłasz" mu pieniądze. Potem cię wyrzuca, a Ty wracasz do domu.

Teraz, kontynuując przykład laika, spójrzmy na kilka Wyjątki. Jeśli zadzwonisz do przyjaciela i nie będzie go w domu, może to być błąd 500. Jeśli zadzwoniłeś i Otrzymałeś wiadomość z odłączonym numerem, ponieważ twój znajomy jest zmęczony pożyczaniem pieniędzy przez cały czas, to nie znaleziono strony 404. Jeśli twój telefon jest martwy, ponieważ nie zapłaciłeś rachunku, może to być IOException. (UWAGA: Ta sekcja może nie być w 100% poprawna. Ma na celu dać ogólne wyobrażenie o tym, co dzieje się w Warunkach laika.)

Pytanie #5:

tak, masz rację, że openConnection po prostu tworzy nowy obiekt połączenia, ale go nie ustanawia. Połączenie jest nawiązywane po wywołaniu getInputStream lub getOutputStream.

openConnection tworzy nowy obiekt połączenia. Z adresu URL .openconnection javadocs :

Nowe połączenie jest otwierane za każdym razem przez wywołanie metody openconnection obsługi protokołu dla tego adresu URL.

The połączenie jest nawiązywane podczas wywoływania openConnection, a strumień wejściowy, strumień wyjściowy lub oba są wywoływane podczas tworzenia ich instancji.

Pytanie #6:

Aby zmierzyć napowietrzność, Zwykle owijam bardzo prosty kod czasu wokół całego bloku połączenia, w ten sposób:

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) );

Jestem pewien, że istnieją bardziej zaawansowane metody pomiaru czasu żądania i kosztów, ale ogólnie jest to wystarczające dla moich potrzeb.

Dla informacji o zamknięciu połączenia, o które nie pytałeś, zobacz w Javie kiedy kończy się połączenie URL?.

 169
Author: jmort253,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-05 13:02:01

Tim Bray przedstawił zwięzły krok po kroku, stwierdzając, że openConnection() nie ustanawia rzeczywistego połączenia. Rzeczywiste połączenie HTTP nie jest nawiązywane, dopóki nie wywołasz metod takich jak getInputStream () lub getOutputStream ().

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

 13
Author: anonymous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-15 23:35:57

W którym momencie HTTPURLConnection próbuje nawiązać połączenie z podanym adresem URL?

Na porcie nazwanym w adresie URL, jeśli istnieje, w przeciwnym razie 80 dla HTTP i 443 dla HTTPS. Wierzę, że to udokumentowane.

W którym momencie mogę wiedzieć, że udało mi się pomyślnie nawiązać połączenie?

Gdy wywołujesz getInputStream () lub getOutputStream () lub getResponseCode () bez uzyskania wyjątku.

Nawiązują połączenie i wysłanie rzeczywistego żądania wykonane w jednym wywołaniu krok / metoda? Jaka to metoda?

Nie i nie.

Czy możesz wyjaśnić funkcję getOutputStream i getInputStream w pojęciu laika?

Każdy z nich najpierw się połączy, jeśli to konieczne, a następnie zwróci wymagany strumień.

Zauważyłem, że gdy serwer, z którym próbuję się połączyć, jest wyłączony, dostaję wyjątek w getOutputStream. Czy to znaczy, że HTTPURLConnection rozpocznie się tylko do ustanowienia połączenie podczas wywoływania getOutputStream? A co z getInputStream? Ponieważ jestem w stanie uzyskać odpowiedź tylko w getInputStream, to czy to znaczy, że nie wysłałem jeszcze żadnego żądania w getOutputStream, ale po prostu ustanawia połączenie? Czy HttpURLConnection wraca do serwera, aby poprosić o odpowiedź, gdy wywołuję getInputStream?

Patrz wyżej.

Czy mam rację mówiąc, że openConnection po prostu tworzy nowy obiekt połączenia, ale nie ustanawia żadnego połączenie już?

Tak.

Jak mogę zmierzyć nadmiarowość odczytu i podłączyć nadmiarowość?

Connect: zwróć czas, jaki getInoutStream() lub getOutputStream() zabiera, niezależnie od tego, które wywołanie jest pierwsze. Czytaj: czas od rozpoczęcia pierwszego czytania do uzyskania EOS.

 1
Author: user207421,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-15 23:45:02

w którym momencie HTTPURLConnection próbuje nawiązać połączenie z podanym adresem URL?

Warto wyjaśnić, istnieje instancja 'UrlConnection' , a następnie podstawowe połączenie z gniazdem TCP/Ip/SSL, 2 różne koncepcje. Instancja 'UrlConnection' lub 'HttpUrlConnection' jest synonimem pojedynczego żądania strony HTTP i jest tworzona podczas wywoływania adresu url.openConnection (). Ale jeśli zrobisz wiele adresów url.openConnection()'s from the one'url' przykład wtedy, jeśli masz szczęście, będą ponownie używać tego samego gniazda Tcp / Ip i SSL handshaking rzeczy...co jest dobre, jeśli robisz wiele żądań stron do tego samego serwera, szczególnie dobre, jeśli używasz SSL, gdzie narzut ustanowienia gniazda jest bardzo wysoki.

Zobacz: implementacja HttpURLConnection

 0
Author: Tim Cooper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:32