2009-12-20 23 views
5

Chúng tôi đang sử dụng API HttpURLConnection để gọi một API REST cho cùng một nhà cung cấp thường xuyên (loại một tập hợp truy vấn). Chúng tôi muốn giữ một nhóm 5 kết nối luôn mở cho máy chủ của nhà cung cấp (luôn là cùng một IP).cách giữ nhiều Java HttpConnections mở đến cùng một đích

Giải pháp thích hợp là gì? Dưới đây là những gì chúng tôi đã thử:


System.setProperty("http.maxConnections", 5); // set globally only once 
... 
// everytime we need a connection, we use the following 
HttpURLConnection conn = (HttpURLConnection) (new URL(url)).openConnection(); 
conn.setRequestMethod("GET"); 
conn.setDoInput(true); 
conn.setDoOutput(false); 
conn.setUseCaches(true); 
... 
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
... 

Tại thời điểm này, chúng tôi đọc luồng đầu vào cho đến khi BufferedReader trả về không còn byte. Chúng tôi làm gì sau thời điểm đó nếu chúng tôi muốn sử dụng lại kết nối cơ bản cho nhà cung cấp? Chúng tôi đã có ấn tượng rằng nếu luồng đầu vào hoàn toàn được đọc, kết nối sẽ được thêm trở lại vào hồ bơi.

Đó là được làm việc trong vài tuần theo cách này, nhưng ngày nay nó đã ngừng làm việc sản xuất hợp ngoại lệ này: java.net.SocketException: Too many open files

Chúng tôi tìm thấy nhiều ổ cắm ở bang CLOSE_WAIT như thế này (bằng cách chạy lsof): java 1814 root 97u IPv6 844702 TCP colinux:58517->123.123.254.205:www (CLOSE_WAIT)

Won hoặc conn.getInputStream(). close() hoặc conn.disconnect() đóng hoàn toàn kết nối và xóa nó khỏi nhóm?

Trả lời

4

Từ here:

Việc thực hiện không đệm cơ thể phản ứng. Điều đó có nghĩa là ứng dụng phải hoàn thành việc đọc nội dung phản hồi hoặc gọi gần() để từ bỏ phần còn lại của nội dung phản hồi, để kết nối đó được sử dụng lại. Hơn nữa, việc thực hiện hiện tại sẽ không cố gắng đọc khối khi làm sạch kết nối, có nghĩa là nếu toàn bộ cơ thể phản hồi không có sẵn, kết nối sẽ không được sử dụng lại.

Tôi đọc như thể giải pháp của bạn sẽ hoạt động, nhưng bạn cũng được tự do gọi gần và kết nối sẽ vẫn được sử dụng lại.

4

Chúng tôi cũng gặp sự cố này trên Java 5 và giải pháp của chúng tôi là chuyển sang Apache HttpClient bằng trình quản lý kết nối gộp chung.

Việc triển khai tiện lợi của trình xử lý URL của Mặt trời đối với HTTP rất bị lỗi. Không có chuỗi bảo trì nào để đóng các kết nối không hoạt động.

Một vấn đề lớn hơn với việc giữ gìn là bạn cần xóa câu trả lời. Nếu không, kết nối sẽ bị mồ côi. Hầu hết mọi người không xử lý chính xác luồng lỗi. Hãy xem câu trả lời của tôi cho câu hỏi này cho một ví dụ về cách đọc phản ứng lỗi một cách chính xác,

HttpURLConnection.getResponseCode() returns -1 on second invocation

+0

Cảm ơn, bạn là đúng, chúng tôi đã không đọc dòng lỗi trong quá trình một lỗi. Điều gì về 'stream.close()' và 'conn.disconnect()'? Họ có ok để sử dụng hoặc họ sẽ đánh bại mục đích của http giữ sống? Tôi đọc một nơi nào đó khi tôi đã viết mã mà bạn nên đọc hoàn toàn luồng, nhưng không đóng nó, nhưng tôi không thể tìm thấy tài liệu tham khảo. – Lightbeard

+0

Bạn không nên đóng luồng cũng như ngắt kết nối nếu muốn sử dụng lại kết nối. Như tôi đã nói, vẫn có thể có rò rỉ ổ cắm ngay cả khi bạn làm mọi thứ đúng, ít nhất là trên Java 5. –

2

Các reference trích dẫn bởi không nhận được những gì thực sự đã giúp.

Chúng tôi biết Apache HttpClient là tốt hơn, nhưng điều đó sẽ yêu cầu một bình khác và chúng tôi có thể sử dụng mã này trong một applet.

Gọi số HttpURLConnection.connect() là không cần thiết. Tôi không chắc liệu nó có ngăn chặn việc tái sử dụng kết nối hay không, nhưng chúng tôi đã lấy nó ra. Việc đóng luồng là an toàn, nhưng việc gọi disconnect() trên kết nối sẽ ngăn không cho sử dụng lại. Ngoài ra, thiết lập sun.net.http.errorstream.enableBuffering=true sẽ giúp.

Dưới đây là những gì chúng ta đã kết thúc bằng:


System.setProperty("http.maxConnections", String.valueOf(CONST.CONNECTION_LIMIT)); 
System.setProperty("sun.net.http.errorstream.enableBuffering", "true"); 

... 

int responseCode = -1; 
HttpURLConnection conn = null; 
BufferedReader reader = null; 
try { 
conn = (HttpURLConnection) (new URL(url)).openConnection(); 
conn.setRequestProperty("Accept-Encoding", "gzip"); 

// this blocks until the connection responds 
InputStream in = new GZIPInputStream(conn.getInputStream()); 

reader = new BufferedReader(new InputStreamReader(in)); 
StringBuffer sb = new StringBuffer(); 
char[] buff = new char[CONST.HTTP_BUFFER_SIZE]; 
int cnt; 

while((cnt = reader.read(buff)) > 0) sb.append(buff, 0, cnt); 

reader.close(); 

responseCode = conn.getResponseCode(); 
if(responseCode != HttpURLConnection.HTTP_OK) throw new IOException("abnormal HTTP response code:"+responseCode); 

return sb.toString(); 

} catch(IOException e) { 
    // consume error stream, otherwise, connection won't be reused 
    if(conn != null) { 
    try { 
     InputStream in = ((HttpURLConnection)conn).getErrorStream(); 
     in.close(); 
     if(reader != null) reader.close(); 
    } catch(IOException ex) { 
     log.fine(ex); 
    } 
    } 

    // log exception  
    String rc = (responseCode == -1) ? "unknown" : ""+responseCode; 
    log.severe("Error for HttpUtil.httpGet("+url+")\nServer returned an HTTP response code of '"+rc+"'"); 
    log.severe(e); 
} 
Các vấn đề liên quan