2011-02-03 33 views
11

Tôi hơi bối rối về cách tránh ổ cắm bị treo khi đọc. Đây là mã của tôi:Luồng đầu vào ổ cắm bị treo khi đọc lần cuối. Cách tốt nhất để xử lý điều này?

Socket socket = new Socket("someMachine", 16003); 
    OutputStream outputStream = socket.getOutputStream(); 
    InputStream inputStream = socket.getInputStream(); 
    try { 
     outputStream.write(messageBuffer.toByteArray()); 
     outputStream.flush(); 
     BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); 
     StringBuffer response = new StringBuffer(); 
     int result; 
     while ((result = in.read()) != -1) { 
      response.append(Character.toChars(result)); 
      System.out.println(result); 
     } 
     System.out.println("Done!"); //never gets printed 
    } catch (...) {} 

Mã trên đọc thành công tất cả dữ liệu từ luồng nhưng sau đó bị treo. Đọc lên trên mạng tôi đã mong đợi để nhận được một -1 từ máy chủ (mà tôi không thể kiểm soát) để cho biết rằng tôi đã đạt đến cuối dòng nhưng thay vào đó tôi có được điều này:

(Lots of data above this point) 
57 
10 
37 
37 
69 
79 
70 
10 

Sau đó nó bị treo . Vì vậy, câu hỏi của tôi là:

1) Tôi đã mã hóa sai hoặc có vấn đề với phản hồi của máy chủ không?

2) Nếu có sự cố với phản hồi của máy chủ (nghĩa là không có -1 được trả lại), làm cách nào tôi có thể làm việc này (tức là dừng đọc khi bị treo).

Bất kỳ trợ giúp nào được đánh giá cao!

+0

là "someMachine" đóng socket sau khi gửi byte cuối cùng? là nó chờ đợi một số trả lời/thừa nhận để làm như vậy? –

+1

có thể trùng lặp của [vấn đề tắc nghẽn Java ....] (http://stackoverflow.com/questions/2797087/java-deadlock-problem) – finnw

+0

được sửa trong trường hợp của tôi khi tôi thêm vào, ở cuối phía máy chủ, ' socket.close() 'hoặc' socket.shutdownOutput() ' –

Trả lời

12

Vấn đề với chỉ dừng ở đâu đọc sẽ treo là điều này có thể xảy ra trong 2 trường hợp:

1: máy chủ không có bất kỳ dữ liệu nhiều hơn để gửi

2: Các máy chủ đã gửi nhiều dữ liệu hơn , nhưng khách hàng của bạn chưa nhận được nó do quá tải mạng.

Và bạn chỉ muốn thực sự dừng đọc trong trường hợp đầu tiên, nhưng bạn muốn đọc để chặn trong trường hợp thứ hai.

Cách để giải quyết vấn đề này là thực hiện giao thức truyền (Chuẩn) cho phép máy chủ thông báo cho khách hàng biết số lượng dữ liệu mong muốn gửi.

Nếu máy chủ biết trước tổng kích cỡ dữ liệu, chỉ cần bắt đầu bằng cách gửi tổng số byte trong quá trình truyền và sau đó gửi dữ liệu. Bằng cách đó, khách hàng biết khi nào nó đã nhận được tất cả dữ liệu.

(Hoặc các máy chủ chỉ có thể đóng kết nối khi hoàn tất. Bằng cách đó read nên thất bại, nhưng công việc chỉ này nếu bạn không cần kết nối trong tương lai)

+0

Vâng, tôi nghĩ bạn đã có được trái tim của điều này. Tôi có một tiêu đề có độ dài nội dung, tôi có thể tận dụng lợi thế mà tôi nghĩ rằng nó sẽ hoạt động. Cảm ơn! –

1

Hãy thử:

while ((result = in.read()) != null) { 
+3

Điều này không biên dịch như in.read() trả về một' int' không thể so sánh với 'null'. Tôi nghĩ rằng thay vào đó bạn có nghĩa là để nói 'while ((result = in.readLine())! = Null) {', nhưng điều này không hoạt động hoặc. –

+1

Ngoài ra, đọc là cuộc gọi chặn. Điều này sẽ treo khóa lên tread. Nếu bạn đang sử dụng bất kỳ multihreading này sẽ khóa một bộ xử lý – JustinDanielson

5

Tôi nghĩ rằng bạn sẽ chỉ nhận được -1 khi máy chủ quyết định dừng cuộc nói chuyện, ví dụ: đóng dòng sản lượng của nó hoặc đóng socket hoàn toàn. Khác, luồng vẫn mở cho dữ liệu đến tiềm năng trong tương lai.

+0

Ah, điểm tốt, đã không nghĩ về điều đó. Tuy nhiên, điều này vẫn khiến tôi gãi đầu mình như thế nào để tôi biết luồng đầu vào của riêng mình đã hoàn thành. –

+0

Đó là vấn đề về định nghĩa giao thức. Loại dữ liệu nào được trao đổi? Nó có cấu trúc không? Liệu nó có một ký tự kết thúc hoặc chuỗi? Nó có chiều dài cố định không? –

2

Tôi không phải là một chuyên gia về Android, nhưng điều này dường như chỉ hoạt động tốt trên Android:

try { 
     telnetClient = new Socket(server, port); 
    } catch (UnknownHostException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    if (telnetClient.isConnected()) { 
     try { 
      InputStream instr = telnetClient.getInputStream(); 
      int buffSize = telnetClient.getReceiveBufferSize(); 
      if (buffSize > 0) { 
       byte[] buff = new byte[buffSize]; 
       int ret_read = instr.read(buff); 
       screen.append(new String(buff, 0, ret_read)); 
      } 
     } catch (IOException e) { 
      screen.append("Exception while reading socket:" + e.getMessage()); 
     } 
    } 
2

Tôi vừa gặp vấn đề tương tự. Tôi đã giải quyết nó bằng cách đặt thời gian chờ ngay sau khi tạo đối tượng ổ cắm ... socket.setSoTimeout (10 * 1000);

0

Tôi thấy vấn đề này khá đáng gờm. Tôi đã cố gắng để thực hiện một lệnh lô cửa sổ từ java và quá trình treo cứng mỗi khi cố gắng để đọc inputstream từ lệnh nhận được thực thi.

Tôi chỉ có thể khắc phục điều này một cách không thận trọng.

a) Bằng cách tìm một dòng cụ thể mà tôi biết sẽ báo hiệu kết thúc thông tin hữu ích tạo thành luồng.
b) Hoặc để bắt đầu một Chủ đề mới, hãy giết quá trình ở đầu kia của ổ cắm, trong trường hợp này là tôi IEDriverServer.exe sau một thời gian chờ đợi.

String[] cmdArray = {"cmd.exe","/c",cmd+ " 2>&1" }; 
    InputStream is = new ProcessBuilder(cmdArray).directory(f).start().getInputStream(); 

     error_buffer = new BufferedReader(new InputStreamReader(is)); 
     int lines=0; 

     while((line=error_buffer.readLine())!=null){ 
      if(line.startsWith("[INFO] Final Memory: ")) { 
       break; 
      } 

      log.debug("Reading cmd Stream "+line); 
      buf.append(line); 
      lines++; 
     } 
Các vấn đề liên quan