HttpURLConnection bağlantı işlemini açıklayabilir misiniz?


134

HTTPURLConnectionBir web servisine bağlanmak için kullanıyorum . Nasıl kullanılacağını biliyorum HTTPURLConnectionama nasıl çalıştığını anlamak istiyorum. Temel olarak, aşağıdakileri bilmek istiyorum:

  • Hangi noktada HTTPURLConnectionbelirtilen URL ile bağlantı kurmaya çalışıyor?
  • Hangi noktada başarılı bir şekilde bağlantı kurabildiğimi bilebilir miyim?
  • Bağlantı kurma ve asıl isteği tek adımda / yöntem çağrısında gönderme işlemi yapılıyor mu? Hangi yöntem?
  • Layman'ın teriminde getOutputStreamve işlevini açıklayabilir misiniz getInputStream? Bağlanmaya çalıştığım sunucu çöktüğünde, bir Exceptionadresim var getOutputStream. Bu HTTPURLConnection, yalnızca çağırdığımda bağlantı kurmaya başlayacağı anlamına mı geliyor getOutputStream? Nasıl getInputStream? Sadece yanıtı alabildiğim için getInputStream, getOutputStreamhenüz bir istek göndermediğim, ancak sadece bir bağlantı kurduğum anlamına mı geliyor? HttpURLConnectionÇalıştırdığımda yanıt istemek için sunucuya geri dönüyor musunuz getInputStream?
  • openConnectionSadece yeni bir bağlantı nesnesi oluşturduğunu ancak henüz herhangi bir bağlantı oluşturmadığını söylemek doğru mudur?
  • Okuma ek yükünü nasıl ölçebilirim ve ek yükü nasıl bağlayabilirim?

Yanıtlar:


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

Sorularınızın ilk 3 yanıtı, yukarıdaki örnek HTTP POST'unda her yöntemin yanında satır içi yorumlar olarak listelenmiştir.

Gönderen getOutputStream :

Bu bağlantıya yazan bir çıkış akışı döndürür.

Temel olarak, bunun nasıl çalıştığını iyi anladığınızı düşünüyorum, bu yüzden layman'ın terimleriyle tekrar edeyim. getOutputStreamtemel olarak veriyi sunucuya yazmak amacıyla bir bağlantı akışı açar . Yukarıdaki kod örneğinde "ileti", sunucuya gönderdiğimiz ve bir yayında kalan yorumu temsil eden bir yorum olabilir. Gördüğünüzde getOutputStream, bağlantı akışını yazmak için açıyorsunuz , ancak arama yapana kadar hiçbir veri yazmıyorsunuz writer.write("message=" + message);.

Gönderen ) (getInputStream :

Bu açık bağlantıdan okunan bir girdi akışı döndürür. Veriler okunabilir duruma gelmeden önce okuma zaman aşımı süresi doluyorsa, döndürülen giriş akışından okuma yapılırken bir SocketTimeoutException bildirilebilir.

getInputStreamtam tersini yapar. Gibi getOutputStream, aynı zamanda bir bağlantı akışı açar , ancak amaç sunucuya veri okumak, ona yazmak değil. Bağlantı veya akış açma başarısız olursa, bir SocketTimeoutException.

GetInputStream'e ne dersiniz? Sadece getInputStream'de yanıt alabildiğim için, henüz getOutputStream'de herhangi bir istek göndermediğim, ancak sadece bir bağlantı kurduğum anlamına mı geliyor?

Bir istek göndermenin ve veri göndermenin iki farklı işlem olduğunu unutmayın. GetOutputStream veya getInputStream öğelerini çağırdığınızda url.openConnection(), sunucuya bağlantı kurmak için bir istek gönderirsiniz. Sunucunun size bağlantının kurulduğunu onayladığı bir el sıkışma vardır. O zaman, veri göndermeye veya almaya hazırsınız. Bu nedenle, istek yapma amacınız veri göndermek olmadıkça, bir akış açmak üzere bağlantı kurmak için getOutputStream öğesini çağırmanız gerekmez .

Layman'ın şartlarına göre, bir getInputStreamistekte bulunmak, arkadaşınızın evine "Hey, gelip bu çift mengene tutamacını ödünç almamın bir sakıncası yok mu?" ve arkadaşınız "Tabii! Gel ve al" diyerek el sıkışmasını kurar. Sonra, o noktada, bağlantı yapılır, arkadaşınızın evine yürür, kapıya vurur, mengene tutamaklarını talep eder ve evinize geri dönersiniz.

Benzer bir örnek kullanmak getOutputStream, arkadaşınızı aramak ve "Hey, size borçlu olduğum param var, size gönderebilir miyim?" Demeyi içerir. İçinde para ve hastaya ihtiyaç duyan arkadaşınız, bunu çok uzun süre tuttuğunuzda, "Tabii, ucuz piçin üzerine gelin" diyor. Yani arkadaşınızın evine yürüyün ve ona parayı "POST". Sonra seni dışarı atıyor ve sen evine geri dönüyorsun.

Şimdi, layman örneğiyle devam edelim, bazı İstisnalara bakalım. Arkadaşınızı aradıysanız ve o evde değilse, bu 500 hata olabilir. Arkadaşınız her zaman para ödünç almaktan yorulduğundan bağlantı kesilmiş bir numara mesajı aradıysanız ve aldıysanız, bu bir 404 sayfası bulunamadı. Faturayı ödemediğiniz için telefonunuz öldüyse, bu bir IOException olabilir. (NOT: Bu bölüm% 100 doğru olmayabilir. Layman'ın terimleriyle ilgili genel bir fikir vermeniz amaçlanmıştır.)

Soru # 5:

Evet, openConnection uygulamasının yeni bir bağlantı nesnesi oluşturduğunu, ancak onu oluşturmadığını haklıyorsunuz. Bağlantı, getInputStream veya getOutputStream öğesini çağırdığınızda kurulur.

openConnectionyeni bir bağlantı nesnesi oluşturur. Gönderen URL.openConnection javadocs :

Bu URL için protokol işleyicisinin openConnection yöntemi çağrılarak her seferinde yeni bir bağlantı açılır.

OpenConnection'ı çağırdığınızda bağlantı kurulur ve bunları başlatırken InputStream, OutputStream veya her ikisi de çağrılır.

Soru # 6 :

Tepegöz ölçmek için, genel olarak tüm bağlantı bloğu etrafında bazı çok basit zamanlama kodu sarın, şöyle:

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

Eminim istek zamanı ve ek yükü ölçmek için daha gelişmiş yöntemler vardır, ancak bu genellikle ihtiyaçlarım için yeterlidir.

Sormadığınız bağlantıları kapatma hakkında bilgi için bkz . Bir URL bağlantısı ne zaman kapanıyor ? Java'da? .


Selam. Teşekkürler!!! Bu gerçekten detaylı bir açıklama ve cevabınızı gerçekten takdir ediyorum. Cevabınızı doğru anlarsam, henüz bir bağlantı kurulmamışsa, hem getOutputStream hem de getInputStream bir bağlantı kurar. Ben getOutputStream çağırırsanız, sonra getInputStream'i çağırırsanız, dahili olarak HTTPURLConnection, getOutStream'de zaten kurabildiğim için artık getInputStream'de bir bağlantı kurmayacak mı? HttpURLConnection getInputStream içinde getOutputStream'de kurabildiğim bağlantıyı yeniden kullanır.
Arci

Devam: Yoksa getOutputStream ve getInputStream için yeni ve ayrı bir bağlantı kuruyor mu? Ayrıca, bağlantı yükünü almak istiyorsanız, zamanlayıcımı koymak için uygun yer getOutputStream'den önce ve sonradır. Okuma yükünü almak istersem, zamanlayıcımı koymak için uygun yer getInputStream'den önce ve sonradır.
Arci

Javadoc'un getInputStream ve getOutputStream ile ilgili söylediklerini hatırlayın: Returns an output stream that writes to this connection.ve Returns an input stream that reads from this open connection.. Çıkış akışı ve giriş akışı bağlantıdan ayrıdır.
jmort253

8
HttpURLConnection nesnesinin yalnızca hedef URL'ye ulaşması gereken noktada ulaştığı görülüyor. Örneğinizde, elbette bağlantı açılana kadar hiçbir şey yapamayan giriş ve çıkış akışlarınız var. Çok daha basit bir durum, bağlantıyı başlatmak ve ardından yanıt kodunu kontrol etmek dışında hiçbir şey yapmadığınız bir GET işlemidir. Bu durumda, getResponseCode () yöntemi çağrılıncaya kadar bağlantı gerçekleşmez. Aksi takdirde, bağlantı yaşam döngüsünün büyük bir açıklaması ve keşfi budur!
Spanky Quigman

1
Daha önce 'UrlConnection' örneği ve altında yatan Tcp / Ip / SSL bağlantısı, 2 ayrı kavram arasında kafam karışmıştı. Birincisi temel olarak tek bir HTTP sayfası isteğiyle eş anlamlıdır. İkincisi, aynı sunucuya birden fazla sayfa isteği yaptığınızda umarım bir kez yaratılacak bir şeydir.
Tim Cooper


1

HTTPURLConnection hangi noktada belirli bir URL ile bağlantı kurmaya çalışır?

Varsa URL'de adlandırılan bağlantı noktasında, aksi takdirde HTTP için 80 ve HTTPS için 443. Bunun belgelendiğine inanıyorum.

Hangi noktada başarılı bir şekilde bağlantı kurabildiğimi bilebilir miyim?

Bir istisna almadan getInputStream () veya getOutputStream () veya getResponseCode () öğesini çağırdığınızda.

Bağlantı kurma ve asıl isteği tek adımda / yöntem çağrısında gönderme işlemi yapılıyor mu? Hangi yöntem?

Hayır ve yok.

LayO'nun teriminde getOutputStream ve getInputStream işlevlerini açıklayabilir misiniz?

Her ikisi de ilk önce gerekirse bağlanır, ardından gerekli akışı döndürür.

Bağlanmaya çalıştığım sunucu çöktüğünde getOutputStream'de bir istisna alıyorum. HTTPURLConnection öğesinin yalnızca getOutputStream öğesini çağırdığımda bağlantı kurmaya başlayacağı anlamına mı geliyor? GetInputStream'e ne dersiniz? Sadece getInputStream'de yanıt alabildiğim için, henüz getOutputStream'de herhangi bir istek göndermediğim, ancak sadece bir bağlantı kurduğum anlamına mı geliyor? HttpURLConnection getInputStream öğesini çağırdığımda yanıt istemek için sunucuya geri dönüyor mu?

Yukarıyı görmek.

OpenConnection'ın yeni bir bağlantı nesnesi oluşturduğunu ancak henüz herhangi bir bağlantı oluşturmadığını söylemek doğru mudur?

Evet.

Okuma ek yükünü nasıl ölçebilirim ve ek yükü nasıl bağlayabilirim?

Bağlanın: hangisini önce çağırırsanız alın, getInoutStream () veya getOutputStream () öğesinin dönmesi için zaman ayırın. Okuma: ilk okumadan EOS almaya kadar geçen süre.


1
Bence OP hangi noktada bağlantının kurulduğu ve hangi noktada bağlantı durumunu öğrenebileceğimiz anlamına geliyordu. Bağlantı noktası URL'si bağlanmadı. Bu openConnection () ve getInoutStream () / getOutputStream () / getResponseCode () için daha sonra cevap doğru yönelik tahmin ediyorum.
Aniket Thakur

1

HTTPURLConnection hangi noktada belirli bir URL ile bağlantı kurmaya çalışır?

Netleştirmeye değer, 'UrlConnection' örneği var ve temelde 2 farklı kavram olan Tcp / Ip / SSL soket bağlantısı var . 'UrlConnection' veya 'HttpUrlConnection' örneği tek bir HTTP sayfası isteğiyle eşanlamlıdır ve url.openConnection () öğesini çağırdığınızda oluşturulur. Ancak bir 'url' örneğinden birden fazla url.openConnection () yaparsanız, şanslıysanız, aynı Tcp / Ip soketini ve SSL el sıkışma şeylerini tekrar kullanırlar ... aynı sunucuya çok sayıda sayfa isteği yapmak, özellikle de soketi kurmanın ek yükünün çok yüksek olduğu SSL kullanıyorsanız iyidir.

Bakınız: HttpURLConneksiyon uygulaması


0

Düşük seviyeli paket alışverişini yakalamak için egzersize girdim ve ağ bağlantısının sadece getInputStream, getOutputStream, getResponseCode, getResponseMessage gibi işlemler tarafından tetiklendiğini gördüm.

Dropbox'a dosya yüklemek için küçük bir program yazmaya çalıştığımda yakalanan paket değişimi.

resim açıklamasını buraya girin

Aşağıda oyuncak programım ve ek açıklama

    /* 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();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.