2010-08-11 18 views
16

मैंने पढ़ा है कि HttpURLConnection लगातार कनेक्शन का समर्थन करता है, ताकि एकाधिक अनुरोधों के लिए कनेक्शन का पुन: उपयोग किया जा सके। मैंने कोशिश की और दूसरी पोस्ट भेजने का एकमात्र तरीका ओपनकनेक्शन को दूसरी बार कॉल करके था। अन्यथा मुझे एक IllegalStateException मिला ("पहले से जुड़ा हुआ");HttpURLConnection कार्यान्वयन

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 के साथ सत्यापित किया) पर भेजने के है, लेकिन मैं क्यों नहीं समझ सकता (हालांकि यह जो मैं चाहता है) के बाद से मैं डिस्कनेक्ट कहा जाता है: मैं निम्नलिखित का इस्तेमाल किया। मैंने HttpURLConnection के लिए स्रोत कोड की जांच की है और कार्यान्वयन एक ही गंतव्य पर कनेक्शन के रखरखाव कैश रखता है। मेरी समस्या यह है कि मैं यह नहीं देख सकता कि मैंने पहला अनुरोध भेजने के बाद कैश में कनेक्शन कैसे रखा है। डिस्कनेक्ट कनेक्शन बंद कर देता है और डिस्कनेक्ट किए बिना, फिर भी मैं नहीं देख सकता कि कनेक्शन कैश में वापस कैसे रखा जाता है। मैंने देखा कि कैश में सभी निष्क्रिय कनेक्शनों पर जाने के लिए एक रन विधि है (मुझे यकीन नहीं है कि इसे कैसे कहा जाता है), लेकिन मुझे नहीं पता कि कैश में कनेक्शन कैसे वापस रखा गया है। ऐसा लगता है कि एकमात्र ऐसा स्थान httpClient की समाप्त विधि में है लेकिन इसे प्रतिक्रिया के साथ POST के लिए नहीं कहा जाता है। क्या कोई इस पर मेरी सहायता कर सकता है?

संपादित मेरे हित TCP कनेक्शन पुन: उपयोग के लिए एक HttpUrlConnection वस्तु की उचित हैंडलिंग क्या है, है। इनपुट/आउटपुट स्ट्रीम को url.openConnection() के बाद बंद किया जाना चाहिए; प्रत्येक बार नया अनुरोध भेजने के लिए (डिस्कनेक्ट() से परहेज)? यदि हां, तो मैं नहीं देख सकता कि कनेक्शन का पुन: उपयोग कैसे किया जा रहा है जब मैं url.openConnection() को दूसरी बार कॉल करता हूं, क्योंकि कनेक्शन को पहले अनुरोध के लिए कैश से हटा दिया गया है और यह नहीं पता कि यह वापस कैसे लौटाया जा सकता है। क्या यह संभव है कि कनेक्शन को keepalive कैश (बग?) पर वापस नहीं किया गया है, लेकिन ओएस ने अभी तक और नए कनेक्शन पर टीसीपी कनेक्शन जारी नहीं किया है, ओएस buffered कनेक्शन (अभी तक जारी नहीं किया गया) या कुछ समान देता है? EDIT2 केवल संबंधित मैंने पाया JDK_KeepAlive

... जब आवेदन InputStream URLConnection.getInputStream() द्वारा दिया पर करीब() कहता है, JDK के HTTP प्रोटोकॉल हैंडलर की कोशिश करेंगे से था कनेक्शन को साफ करने के लिए और यदि सफल है, तो भविष्य में HTTP अनुरोधों द्वारा पुन: उपयोग के लिए कनेक्शन को कनेक्शन कैश में डाल दें।

लेकिन मुझे यकीन नहीं है कि यह कौन सा हैंडलर है। sun.net.www.protocol.http.Handler कोई कैशिंग नहीं करता जैसा मैंने देखा धन्यवाद!

+0

एक मामले में: http://stackoverflow.com/questions/2457538/several-requests-from-one-httpurlconnection?rq=1 मेरे मामले में मैं भी कई अनुरोध प्राप्त करने किसी भी get/post पैरामीटर के बिना मेरी php फ़ाइल में, जहां पैरामीटर प्राप्त करने के साथ केवल 1 अनुरोध है .... मुझे नहीं पता कि क्यों, अगर HttpURLConnection एक समय में एक अनुरोध भेजने के लिए है, तो सर्वर पर बहुत से अनुरोध भेजना ... – Bhuro

उत्तर

17

इनपुट/आउटपुट धारा को बंद कर दिया जाना चाहिए जा पीछा एक url.openConnection द्वारा(); प्रत्येक बार नया अनुरोध (डिस्कनेक्ट() से परहेज) भेजने के लिए?

हां।

यदि हाँ, मैं यह नहीं देख सकते हैं कि कनेक्शन पुन: उपयोग किया जब मैं url.openConnection() दूसरे समय के लिए फोन किया जा रहा है, के बाद से कनेक्शन पहले अनुरोध के लिए कैश से निकाल दिया गया है और यह नहीं मिल सकता कि यह वापस लौटाया गया है।

आप अंतर्निहित Socket और अपने TCP कनेक्शन अंतर्निहित साथ HttpURLConnection भ्रमित कर रहे हैं। वे वही नहीं हैं। HttpURLConnection उदाहरणों GC'd हैं, अंतर्निहित Socket जमा है, जब तक आप disconnect().

+1

मैंने देखा जब मैंने देखा (Wireshark का उपयोग करके) मैंने कोड कोड को देखना शुरू कर दिया है कि अगर मैंने डिस्कनेक्ट कहा है() टीसीपी कनेक्शन अभी भी पुन: उपयोग किया गया है। यूआरएल कनेक्शन के कैशिंग के लिए एक समवर्ती हैशप है, और मैं देखता हूं कि जब एक नया HttpurlConnection बनाया जाता है, तो पूल में कनेक्शन होने पर यह इसका उपयोग करता है (HttpURLConnection कन्स्ट्रक्टर में)। लेकिन जब मैं स्ट्रीम बंद करता हूं (और पूरी प्रतिक्रिया पढ़ता हूं), तो मैं नहीं देख सकता कि कनेक्शन एलीव कैश में कनेक्शन कैसे रखा जाता है। मैं देखता हूं कि अनुरोध वापस कर दिया गया है यदि अनुरोध एक हेड है (http.finished() कहा जाता है) लेकिन पोस्ट के लिए नहीं। – Cratylus

+0

आप सही हैं सर्वर सॉकेट समवर्ती हैशैप में पूल किए जाते हैं लेकिन एक बार अनुरोध होने के बाद, सॉकेट क्लाइंट वेक्टर से हटा दिया जाता है ताकि एक नया थ्रेड एक नया कनेक्शन बनाना पड़े। लेकिन इस सॉकेट को पूल में वापस जाना होगा। ऐसा लगता है कि केवल putInKeepAliveCache(); में होता है। लेकिन इसे प्रतिक्रिया निकाय के साथ 200 ओके के लिए नहीं कहा जाता है। डिस्कनेक्ट का उपयोग कर टीसीपी कनेक्शन में एक ही व्यवहार को देखना संभव है या नहीं? – Cratylus

+0

नहीं, * सॉकेट * पूल किए गए हैं। इस संदर्भ में कोई सर्वर सॉकेट नहीं है। और जो आपने पाया है वह शायद उन सभी को पूल नहीं किया गया है। – EJP

7
HttpURLConnection के लिए जावाडोक से

(मेरे जोर):

प्रत्येक HttpURLConnection उदाहरण एक ही अनुरोध लेकिन HTTP सर्वर के लिए अंतर्निहित नेटवर्क कनेक्शन बनाने के लिए पारदर्शी रूप से अन्य द्वारा साझा किया जा सकता है प्रयोग किया जाता है उदाहरणों। InputStream पर पास() पद्धतियों या एक HttpURLConnection की OutputStream एक अनुरोध के बाद कॉलिंग नेटवर्क इस उदाहरण के साथ जुड़े संसाधनों मुक्त कर सकते हैं, लेकिन कोई प्रभाव नहीं पर किसी भी लगातार कनेक्शन साझा है।कॉलिंग डिस्कनेक्ट() विधि अंतर्निहित सॉकेट को बंद कर सकता है यदि एक सतत कनेक्शन अन्यथा समय पर निष्क्रिय हो जाता है।

+0

मैंने इसे पढ़ लिया है। मेरा सवाल यह है कि अन्य मामलों द्वारा बफर में कनेक्शन कैसे साझा किया जाता है। मुझे वह कोड नहीं मिल रहा है जो कैश – Cratylus

+1

से कनेक्शन लौटाता है, मुझे यकीन नहीं है कि आपकी चिंता क्या है। क्या आप ऐसे व्यवहार को देख रहे हैं जो आपको कार्यान्वयन में एक बग पर संदेह करता है? –

+0

मैंने देखा एक बार मैंने कोड कोड को देखना शुरू कर दिया (वायरशर्क का उपयोग करके) कि अगर मैंने डिस्कनेक्ट कहा() टीसीपी कनेक्शन अभी भी पुन: उपयोग किया गया था। स्रोत में मैं पहले अनुरोध के इनपुट स्ट्रीम को बंद करने के बाद keepAlive कैश में वापस कनेक्शन को नहीं देख सका। तो अगर मैं डिस्कनेक्ट() या नहीं कहता तो कोई फर्क नहीं पड़ता। यह मुझे चिंतित करता है कि कार्यान्वयन में शायद कुछ प्रकार का मुद्दा है जब तक कि मुझे कुछ याद नहीं आ रहा है – Cratylus

4

फोन मैंने पाया कि कनेक्शन वास्तव में कैश किया गया है जब InputStream बंद कर दिया है। एक बार इनपुटस्ट्रीम बंद हो जाने के बाद अंतर्निहित कनेक्शन buffered है। हालांकि, HttpURLConnection ऑब्जेक्ट आगे के अनुरोधों के लिए उपयोग करने योग्य नहीं है, क्योंकि ऑब्जेक्ट को अभी भी "कनेक्ट" माना जाता है, यानी इसके बूलियन कनेक्ट को सत्य पर सेट किया गया है और कनेक्शन को बैफर में वापस रखे जाने के बाद साफ़ नहीं किया जाता है। इसलिए हर बार एक नया एचटीपीयूआरएल कनेक्शन को एक नए पोस्ट के लिए तत्काल चालू किया जाना चाहिए, लेकिन अंतर्निहित टीसीपी कनेक्शन का पुन: उपयोग किया जाएगा, अगर इसका समय समाप्त नहीं हुआ है। तो ईजेपी उत्तर सही वर्णन था। डिस्कनेक्ट() को ओएस द्वारा किए गए कैशिंग के कारण स्पष्ट रूप से कॉल करने के बावजूद मैंने देखा व्यवहार (टीसीपी कनेक्शन का पुन: उपयोग) हो सकता है? मुझे नहीं पता। मुझे उम्मीद है कि जो कोई जानता है वह समझा सकता है। धन्यवाद।

+1

नहीं, मुझे नहीं लगता कि ओएस ऐसा कर सकता है। HTTP 1 के उपयोग को मजबूर कर, बंद करने के लिए एक तरीका है।0 (जो निरंतर कनेक्शन का समर्थन नहीं करता है), या "कनेक्शन: क्लोज़" हेडर का उपयोग करके, यदि आप वास्तव में अंतर्निहित टीसीपी संश्लेषण के किसी भी साझाकरण को नहीं चाहते हैं। – StaxMan

+0

@StaxMan: मुझे HTTP में कनेक्शन हेडर के बारे में पता है। मेरा भ्रम इस तथ्य के कारण था, भले ही मैंने अंतर्निहित सॉकेट को स्पष्ट रूप से बंद कर दिया, फिर भी कनेक्शन का पुन: उपयोग किया गया। मेरे दिमाग में जिस व्यवहार की मैं अपेक्षा कर रहा था वह 3-तरफा हैंडशेक और एक नए टीसीपी कनेक्शन पर एक HTTP कनेक्शन के कारण 2 (अधिकतम) सेक देरी थी। मैंने यह नहीं देखा और मैंने सोचा कि यह ओएस कैशिंग – Cratylus

+0

से संबंधित कुछ था स्पष्टीकरण के लिए ठीक है धन्यवाद। – StaxMan

2

हम्म। मैं यहाँ कुछ याद आ रही हो सकता है (क्योंकि यह कोई पुराना सवाल है), लेकिन जहाँ तक मुझे पता है, वहाँ 2 प्रसिद्ध अंतर्निहित TCP कनेक्शन के समापन के लिए मजबूर करने के कई तरीके हैं: HTTP 1.0 के

  • बल प्रयोग (1.1 लगातार कनेक्शन पेश किए गए) - जैसा कि http अनुरोध लाइन
  • द्वारा इंगित किया गया है 'मान' के साथ 'कनेक्शन' शीर्षलेख भेजें; यह भी बंद करने के लिए मजबूर करेगा।
+0

जेडीके के HttpUrlConnection का उपयोग करके आप "HTTP1.0 का उपयोग कैसे करें"? – Cratylus

+0

हम्म। अच्छा सवाल - मैंने माना कि एक रास्ता था, लेकिन मुझे जल्दी googling के साथ एक नहीं मिला। तो मैं दूसरे समाधान का उपयोग करूंगा; यह किसी भी तरह से बेहतर है, और इस उद्देश्य के लिए भी काम करता है। – StaxMan

4

कैसे आप "HTTP1.0 के बल प्रयोग" JDK के HttpUrlConnection का उपयोग कर सकते हैं?

HTTP1.1 कनेक्शन के लिए खंड „Persistent Connections” of the Java 1.5 guide समर्थन के अनुसार बंद कर दिया या जावा संपत्ति http.keepAlive (डिफ़ॉल्ट सच है) का उपयोग करने पर किया जा सकता है। इसके अलावा, जावा संपत्ति http.maxConnections किसी भी समय किसी गंतव्य पर रहने के लिए प्रति गंतव्य अधिकतम (समवर्ती) कनेक्शन इंगित करता है।

इसलिए, जावा प्रॉपर्टी http.keepAlive को गलत पर सेट करके पूरे एप्लिकेशन के लिए "HTTP1.0 का बल उपयोग" लागू किया जा सकता है।

0

धाराओं को छोड़कर निष्क्रिय टीसीपी कनेक्शन का कारण बन जाएगा। प्रतिक्रिया धारा पूरी तरह से पढ़ा जाना चाहिए। एक और चीज जिसे मैंने शुरुआत में अनदेखा किया था, और इस विषय पर अधिकतर उत्तरों में अनदेखी देखी गई है, अपवादों के मामले में त्रुटि धारा से निपटने के लिए भूल रही है। इस के समान कोड मेरी क्षुधा है कि संसाधनों का ठीक से रिहा नहीं किया गया था में से एक तय:

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

बफ़र पाठक सख्ती से आवश्यक नहीं है, मैं इसे चुना क्योंकि मेरी उपयोग के मामले एक बार में एक पंक्ति को पढ़ने की आवश्यकता है।

यह भी देखें: http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html

+0

आपको ईओएस, या त्रुटि स्ट्रीम को स्ट्रीम पढ़ने की आवश्यकता नहीं है। आपको बस बंद करना है। अपना उद्धरण देखें। Buffered पाठक को बंद करना स्ट्रीम बंद कर देगा ताकि आपको इसकी आवश्यकता न हो। -1 – EJP

संबंधित मुद्दे