2010-02-22 39 views
113

Tôi đang sử dụng apache commons http khách hàng để gọi url bằng cách sử dụng phương pháp đăng bài để gửi các thông số và nó là ném các lỗi dưới đây hiếm khi.Cách khắc phục java.net.SocketException: Đường ống bị hỏng?

java.net.SocketException: Broken pipe 
     at java.net.SocketOutputStream.socketWrite0(Native Method) 
     at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92) 
     at java.net.SocketOutputStream.write(SocketOutputStream.java:136) 
     at java.io.BufferedOutputStream.write(BufferedOutputStream.java:105) 
     at java.io.FilterOutputStream.write(FilterOutputStream.java:80) 
     at org.apache.commons.httpclient.methods.ByteArrayRequestEntity.writeRequest(ByteArrayRequestEntity.java:90) 
     at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499) 
     at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114) 
     at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096) 
     at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398) 

Ai đó có thể đề xuất điều gì gây ra ngoại lệ này và cách gỡ lỗi?

+0

Tần suất (số lần mỗi giây) bạn thực hiện cuộc gọi của mình? – Roman

+0

5-10 cuộc gọi mỗi giây. –

+1

cách tốt nhất là thử http://stackoverflow.com/questions/10142409/write-an-inputstream-to-an-httpservletresponsev –

Trả lời

57

Điều này được gây ra bằng cách ghi vào kết nối khi đầu kia đã đóng.

Vì vậy, bạn có giao thức ứng dụng được xác định kém hoặc được triển khai.

+4

Bạn có thể vui lòng giúp tôi xác định và sửa không? Về cơ bản, làm thế nào để xác nhận lý do và sửa chữa? –

+4

Tôi * đã * xác nhận lý do. Bạn đang viết trong khi đầu kia đã đóng kết nối. Việc sửa chữa không phải là để làm điều đó. Khi đầu kia không đọc nó, không có bất kỳ điểm nào. Như tôi cũng đã nói, nếu điều này xảy ra, có điều gì đó không ổn với đặc tả hoặc triển khai giao thức ứng dụng của bạn, có thể là bạn thậm chí không có. – EJP

+0

Cảm ơn. Ứng dụng phía máy chủ đã được triển khai bằng giao thức HTTP. Nó đang chạy dưới tomcat. Tôi có phạm sai lầm nào khi chỉ định tiêu đề không? Ngoài ra, có thể xác định liệu đầu kia đã đóng kết nối trong mã phía máy khách không? –

1

Tôi đã triển khai chức năng tải xuống dữ liệu qua máy chủ FTP và cũng tìm thấy cùng một ngoại lệ trong khi tiếp tục tải xuống đó. Để giải quyết ngoại lệ này, bạn sẽ luôn phải ngắt kết nối khỏi phiên trước đó và tạo phiên bản mới của Máy khách và kết nối mới với máy chủ. Cách tiếp cận tương tự này cũng có thể hữu ích cho HTTPClient.

+0

Để giải quyết lỗi này, bạn phải tránh sử dụng các ổ cắm kín. – EJP

+1

LOL. Bạn có thể lãng phí tất cả các ngày điều chỉnh tất cả các lời khuyên không có thật về SO. – Dave

+2

@Dave Thật vậy. Đôi khi tôi làm. – EJP

19

Trong trường hợp của chúng tôi, chúng tôi đã trải nghiệm điều này trong khi thực hiện kiểm tra tải trên máy chủ ứng dụng của chúng tôi. Vấn đề hóa ra là chúng ta cần thêm bộ nhớ bổ sung vào JVM của mình vì nó đã hết. Điều này giải quyết được vấn đề.

Thử tăng bộ nhớ khả dụng cho JVM và hoặc theo dõi mức sử dụng bộ nhớ khi bạn gặp phải các lỗi đó.

+3

Tôi gặp vấn đề tương tự trong khi kiểm tra tải. Tôi đoán các dữ liệu mất rất nhiều thời gian để được tạo ra và công cụ kiểm tra tải không chờ đợi dữ liệu đủ lâu sau đó nó đóng kết nối. Tôi trường hợp của bạn, thêm bộ nhớ có thể đã giảm thời gian quá trình tạo dữ liệu để kiểm tra tải có tất cả dữ liệu mà không có giới hạn thời gian chờ. Một giải pháp thay thế để tăng bộ nhớ là tăng thời gian chờ của công cụ kiểm tra tải. –

+1

Rõ ràng bộ nhớ thấp khiến ứng dụng đóng chốt nhận hoặc thực sự thoát hoàn toàn, với cùng tác dụng. Bộ nhớ thấp * tự nó * không gây ra các ống bị hỏng. – EJP

3

Tất cả các dòng đang mở & kết nối cần phải được đóng đúng cách, vì vậy lần sau chúng tôi cố gắng sử dụng đối tượng urlConnection, nó không phát sinh lỗi. Ví dụ, thay đổi mã sau đây đã sửa lỗi cho tôi.

Trước:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); 
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out)); 
bw.write("Some text"); 
bw.close(); 
out.close(); 

Sau:

OutputStream os = urlConnection.getOutputStream(); 
OutputStream out = new BufferedOutputStream(os); 
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out)); 
bw.write("Some text"); 
bw.close(); 
out.close(); 
os.close(); // This is a must. 
+5

Điều này thực sự rất lạ, bởi vì một 'BufferedOutputStream' luôn gọi' close() 'trên luồng đầu ra cơ bản của nó (do đó trên luồng đầu ra của' urlConnection'). Xem http://docs.oracle.com/javase/6/docs/api/java/io/BufferedOutputStream.html và http://docs.oracle.com/javase/6/docs/api/java/io /FilterOutputStream.html#close() Vì vậy, khi bạn gọi 'os.close()', nó phải được đóng lại rồi. Không? – obecker

+2

'os.close()' không phải là 'phải'. Không phải là 'out.close()' cho vấn đề đó. 'bw.close()' là đủ. @obedker là chính xác. Chỉ riêng sự thay đổi này không thể khắc phục được sự cố. – EJP

-1

javadoc:

Chiều dài hàng đợi tối đa đối với chỉ dẫn kết nối đến (một yêu cầu để kết nối) được thiết lập đến 50. Nếu chỉ báo kết nối đến khi hàng đợi đầy, kết nối sẽ bị từ chối.

Bạn nên tăng "tồn đọng" tham số của ServerSocket của bạn, ví dụ

int backlogSize = 50 ; 
new ServerSocket(port, backlogSize); 
+0

Tăng việc tồn đọng sẽ không giải quyết được lỗi 'hỏng đường ống'. – EJP

+0

nhưng nó đã giúp tôi – TheSecond

+0

@EJP Tôi đã thử nghiệm một máy chủ trên Linux và nó hoạt động, nhưng trên Mac OS - không. Và tăng kích thước backlog đã giúp tôi. Tôi không biết rằng kích thước tối đa là 50. – TheSecond

0

Vấn đề này có thể là các file được triển khai của bạn không được cập nhật với các phương pháp RMI đúng. Kiểm tra xem giao diện RMI của bạn đã cập nhật các thông số hay cấu trúc dữ liệu cập nhật mà máy khách của bạn chưa có. Hoặc máy khách RMI của bạn không có tham số nào khác với các phiên bản máy chủ của bạn.

Đây chỉ là một phỏng đoán được giáo dục. Sau khi triển khai lại các tệp lớp của ứng dụng máy chủ của tôi và kiểm tra lại, vấn đề của "Broken pipe" đã biến mất.

1

Nguyên nhân là đồng nghiệp từ xa đóng ổ cắm của nó (ví dụ như tai nạn), vì vậy nếu bạn cố ghi dữ liệu vào ví dụ, bạn sẽ nhận được dữ liệu này.để giải quyết đó, chèn đọc/ghi tới socket hoạt động giữa:

try { 
     /* your code */ 
} catch (SocketException e) { 
     e.printStackTrace(); 
} 
0

Những câu trả lời ở trên minh họa cho lý do java.net.SocketException: Broken pipe này: đầu kia đóng kết nối. Tôi muốn chia sẻ kinh nghiệm những gì đã xảy ra khi tôi gặp nó:

  1. trong yêu cầu của khách hàng, các Content-Type tiêu đề được nhầm lẫn thiết lập lớn hơn yêu cầu cơ thể thực sự là (trong thực tế không có cơ thể ở tất cả)
  2. sự dịch vụ dưới trong ổ cắm tomcat đang đợi rằng dữ liệu cơ thể có kích thước (http là trên TCP đảm bảo giao hàng bằng cách đóng gói và ...)
  3. khi 60 giây đã hết hạn, tomcat ném thời gian ra ngoại lệ: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception java.net.SocketTimeoutException: null
  4. khách hàng nhận được một phản ứng với mã trạng thái 500 vì ngoại lệ hết thời gian chờ .
  5. kết nối máy khách (vì nó nhận được phản hồi).
  6. tomcat ném java.net.SocketException: Broken pipe vì khách hàng đã đóng cửa.

Đôi khi, tomcat không ném ngoại lệ pip bị hỏng, vì ngoại lệ hết thời gian đóng kết nối, tại sao sự khác biệt này cũng làm tôi khó hiểu.

0

SocketException: Ống bị hỏng, được gây ra bởi 'đầu kia' (Máy khách hoặc máy chủ) đóng kết nối trong khi mã của bạn đang đọc hoặc ghi vào kết nối.

Đây là ngoại lệ rất phổ biến trong ứng dụng khách/máy chủ nhận lưu lượng truy cập từ khách hàng hoặc máy chủ ngoài kiểm soát ứng dụng. Ví dụ, khách hàng là một trình duyệt. Nếu trình duyệt thực hiện cuộc gọi Ajax và/hoặc người dùng chỉ cần đóng trang hoặc trình duyệt, thì điều này có thể tiêu diệt tất cả các giao tiếp bất ngờ một cách hiệu quả. Về cơ bản, bạn sẽ thấy lỗi này bất cứ lúc nào đầu kia chấm dứt ứng dụng của họ, và bạn không dự đoán nó.

Nếu bạn gặp ngoại lệ này trong ứng dụng của mình, điều đó có nghĩa là bạn nên kiểm tra mã nơi IO (Đầu vào/Đầu ra) xuất hiện và bọc nó bằng khối try/catch để bắt IOException này. Đó là sau đó, tùy thuộc vào bạn để quyết định cách bạn muốn xử lý tình huống bán hợp lệ này.

Trong trường hợp của bạn, nơi sớm nhất mà bạn vẫn có quyền kiểm soát là cuộc gọi đến HttpMethodDirector.executeWithRetry - Vì vậy, hãy đảm bảo cuộc gọi đó được gói với khối try/catch và xử lý nó như thế nào bạn thấy phù hợp.

Tôi đặc biệt khuyên bạn không nên ghi lại lỗi cụ thể của SocketException-Broken Pipe ở bất kỳ điều nào khác ngoài mức gỡ lỗi/theo dõi. Khác, điều này có thể được sử dụng như một hình thức của DOS (Denial Of Service) tấn công bằng cách điền vào các bản ghi. Hãy thử và làm cứng và phủ định thử nghiệm ứng dụng của bạn cho trường hợp phổ biến này.

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