2016-05-14 27 views
1

我一直在使用AsychronousSockets,但遇到運行大負載時接收ReadPendingException的問題。使用AsynchronousSocketChannel時的ReadPendingException

一些上下文: 我想客戶端異步發送消息到服務器,然後監聽響應。

響應可以是3種類型中的一種,而AsynchronousSocketChannel的讀取需要預定大小的ByteBuffer。因此,我的解決方案是有兩個讀取:第一個接收消息的類型(以4字節傳遞,一個int),然後是另一個讀取,它將構造適當大小的字節緩衝區來處理其餘的的消息。

我認爲這裏的主要問題伴隨着這樣一個事實,即當調用CompletetionHandler的完整方法時,並不一定意味着ByteBuffer的讀取完成。爲了解決這個問題,我創建了一個while循環,直到ByteBuffer已滿爲止。

然而,在while循環中讀取的內容似乎偶爾會與其他讀取相沖突,即當我收到ReadPendingException時。

基本骨架代碼:

AsynchronousChannelGroup mThreadGroup= AsynchronousChannelGroup.withFixedThreadPool(100, Executors.defaultThreadFactory()); 
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(mThreadGroup); 
InetSocketAddress hostAddress = new InetSocketAddress("localhost", 12345); 

// Connect to server 
channel.connect(hostAddress, null, new CompletionHandler<Void, Void>() { 
    @Override 
    public void completed(Void result, Void attachment) { 
     // Write some message to server 
     ByteBuffer message = ... 
     channel.write(message, null, new CompletionHandler<Void, Void>() { 

      @Override 
      public void completed(Void result, Void attachment) { 
       // Now that we have sent the message, listen for a response type 
       ByteBuffer responseType = ... 
       channel.read(responseType, null, new CompletionHandler<Void, Void>() { 

        @Override 
        public void completed(Void result, Void attachment) { 
         // parse response type, do some other stuff... 
         // ... 
         // After other stuff, create new byte buffer for main message 
         ByteBuffer receiveMessage = ... 
         channel.read(receiveMessage, null, new CompletionHandler<Void, Void>() { 

          @Override 
          public void completed(Void result, Void attachment) { 
           // The read may not have been completed, so make sure that it is 
           while (receiveMessage.remaining() > 0) { 
            channel.read(receiveMessage); 
           } 

           // Handle receiveMessage... 
          } 
          @Override 
          public void failed(Throwable exc, Void attachment) {} 
         }); 
        } 
        @Override 
        public void failed(Throwable exc, Void attachment) {} 
       }); 
      } 

      public void failed(Throwable exc, Void attachment) {} 
     }); 
    } 

    @Override 
    public void failed(Throwable exc, Void attachment) {} 
}); 

所以我的問題是這樣雙重的:

  1. 有沒有獲得代碼的方式,如上圖所示,正常工作(又名不再接收ReadPendingException)?

  2. 是否有更好的方法來設置相同的功能?

非常感謝你們提供任何可能的幫助。

回答

-1

我覺得這個異常來了,因爲另一個線程正在嘗試調用這個completionHandler。訪問需要在readCompletionHandler上同步。或者,嘗試刪除ReadCompletionHandler中的while(remaining)循環。使用bytesRead參數調用完成的回調函數。使用此值創建讀取消息的緩衝區。對於如:

`類ClientReadCompletionHandler實現CompletionHandler {

private AsynchronousSocketChannel socket; 
private ByteBuffer readBuffer; 

public ClientReadCompletionHandler(AsynchronousSocketChannel socket, ByteBuffer readBuffer) { 
    this.socket = socket; 
    this.readBuffer = readBuffer; 
    System.out.println("readBuffer in constructor: " + readBuffer); 
} 

@Override 
public void completed(Integer bytesRead, IOContext state) { 
    if (bytesRead != null && bytesRead == -1) { 
     try { 
      socket.close(); 
      return; 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    byte[] buffer = new byte[bytesRead]; 
    readBuffer.rewind(); 
    // Rewind the input buffer to read from the beginning 

    readBuffer.get(buffer); 

    if(readBuffer.hasRemaining()) { 
     // process this readBuffer somehow to read all remaining data. 
     // This will not be the place to call socket.read() again. 

    }  
     readBuffer.clear(); 
     IOContext readState = new IOContext(); 
    // Now read from socket again. 
     socket.read(readBuffer, readState, this); 
} 

'

1

你應該讀完成方法內不循環,特別是沒有檢查,看看是否先有所有的數據。你應該先檢查看看您是否獲得了所需的所有數據,然後如果沒有,問題一個更讀,用同樣的方法完成。該過程將遞歸到滿足第一個測試。

相關問題