2012-06-27 34 views
9

Tôi đang sử dụng DefaultHttpClient với số ThreadSafeClientConnManager trên Android (2.3.x) để gửi các yêu cầu HTTP đến máy chủ REST của tôi (trình kết nối được nhúng).Tại sao DefaultHttpClient gửi dữ liệu qua ổ cắm nửa đóng?

Sau ~ 200 giây không hoạt động, máy chủ sẽ đóng kết nối TCP bằng [FIN]. Ứng dụng khách Android phản hồi với [ACK]. Điều này nên và không để lại socket trong trạng thái nửa đóng (máy chủ vẫn đang nghe, nhưng không thể gửi dữ liệu). Tôi mong rằng khi khách hàng cố gắng sử dụng lại kết nối đó (thông qua HttpClient.execute), DefaultHttpClient sẽ phát hiện trạng thái nửa đóng, đóng socket ở phía máy khách (do đó gửi [FIN/ACK] để hoàn thành đóng) và mở một kết nối mới cho yêu cầu. Nhưng, có chà.

Thay vào đó, nó sẽ gửi yêu cầu HTTP mới qua ổ cắm nửa đóng. Chỉ sau khi gửi là trạng thái nửa đóng được phát hiện và socket đóng trên phía máy khách (với [FIN] được gửi đến máy chủ). Tất nhiên, máy chủ không thể đáp ứng yêu cầu (nó đã gửi [FIN]), vì vậy máy khách cho rằng yêu cầu thất bại và tự động thử lại thông qua một socket/kết nối mới.

Kết quả cuối cùng là máy chủ sẽ xem và xử lý hai bản sao của yêu cầu.

Bất kỳ ý tưởng nào về cách sửa lỗi này? (Máy chủ của tôi thực hiện điều chính xác với bản sao thứ hai, nhưng tôi thấy khó chịu rằng tải trọng được truyền hai lần.)

Không nên mặc địnhHttpClient phát hiện rằng socket đã được đóng khi lần đầu tiên cố gắng viết gói HTTP mới, đóng ổ cắm đó ngay lập tức và bắt đầu một ổ cắm mới? Tôi đang bối rối như thế nào một yêu cầu HTTP mới được gửi vào một phút ổ cắm sau khi máy chủ gửi một [FIN].

+0

'AndroidHttpClient' không hành vi tương tự chính xác (ví dụ: một' DefaultHttpClient' với một 'ThreadSafeClientConnManager' để đảm bảo an toàn thread) ... có lẽ bạn có thể thử sử dụng đó? Tôi không biết nhiều về các chi tiết về cách kết nối ổ cắm hoạt động, nhưng chỉ là một gợi ý ... –

Trả lời

5

Đây là giới hạn chung của I/O chặn trong Java. Chỉ đơn giản là không có cách nào để tìm ra liệu điểm cuối đối diện có đóng kết nối không bằng cách cố gắng đọc từ socket. Apache HttpClient làm việc vấn đề này xung quanh bằng cách sử dụng kiểm tra kết nối cũ mà cơ bản là một hoạt động đọc rất ngắn. Tuy nhiên, kiểm tra có thể và thường bị vô hiệu hóa. Trong thực tế nó thường được khuyến khích để có nó bị vô hiệu hóa do độ trễ thêm kiểm tra giới thiệu. Tôi không biết chính xác phiên bản của HttpClient được vận chuyển với Android hoạt động như thế nào nhưng bạn có thể thử cho phép kiểm tra một cách rõ ràng bằng cách sử dụng một tham số cấu hình thích hợp.

Giải pháp tốt hơn cho vấn đề này có thể là loại bỏ kết nối khỏi nhóm kết nối không hoạt động trong một khoảng thời gian cụ thể (150 giây) sau một khoảng thời gian không hoạt động.

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e652

+0

Cảm ơn. Tôi đã bật kiểm tra kết nối cũ nhưng kiểm tra vẫn chưa được thực hiện trên Android. Nó được thực hiện với một bình, vani HttpClient độc lập. Có lẽ đội Android thực sự đã làm rối tung với những kẻ xâm nhập của HttpClient khi họ nhập vào bản Repos của Android. Tôi nghĩ rằng tôi sẽ lấy đề xuất gợi ý kết nối nhàn rỗi. –

+1

@David B. Google sử dụng Adnroid dựa trên phiên bản Apache HttpClient cực kỳ lỗi thời (pre BETA 4.0). Đó là các kỹ sư chính đáng của Google có thể đã xóa kiểm tra kết nối cũ. – oleg

Các vấn đề liên quan