2010-07-08 61 views
3

我的BlackBerry OS 5上的網絡I/O代碼有問題。網絡I/O掛在BlackBerry OS 5上

在我的I/O操作期間,我不斷收到零星的掛起和最終的TCP超時異常。

我使用5.0網絡API來建立每次完美工作的連接。

問題在於執行實際的I/O時。我有一個後臺工作線程來處理來自隊列的I/O請求。只有一個後臺線程,所以所有請求都被序列化到這個線程上。

完成通知是通過請求排隊時傳入的委託接口完成的。

完成委託調用後臺工作線程,但客戶可以自由通過invokeLater重新發布這事件線程做UI更新等

注:
HttpRequest的是我自己的類擁有關於請求的數據。
MutableData是我自己的類,它保存讀取的數據。
BUFFER_SIZE = 2048

HttpConnection getConnectionForRequest(final HttpRequest inRequest) { 
    final String url = inRequest.getURL(); 
    final int[] availableTransportTypes = 
     TransportInfo.getAvailableTransportTypes(); 
    final ConnectionFactory connectionFactory = new ConnectionFactory(); 
    connectionFactory.setPreferredTransportTypes(availableTransportTypes); 
    connectionFactory.setConnectionMode(ConnectionFactory.ACCESS_READ); 
    final ConnectionDescriptor connectionDescriptor = 
     connectionFactory.getConnection(url); 
    HttpConnection connection = null; 
    if (connectionDescriptor != null) { 
     connection = (HttpConnection) connectionDescriptor.getConnection(); 
    } 
    return connection; 
} 

public void run() { 
    while (isRunning()) { 
     // This blocks waiting on a request to appear in the queue. 
     final HttpRequest request = waitForRequest(); 
     final HttpConnection connection = getConnectionForRequest(request); 
     final MutableData data = new MutableData(); 
     final InputStream inputStream = connection.openInputStream(); 
     final byte[] readBuffer = new byte[BUFFER_SIZE]; 
     int chunkSize; 
     // *** The following read call sporadically hangs and eventually throws 
     // a TCP timeout exception. 
     while((chunkSize = inputStream.read(readBuffer, 0, BUFFER_SIZE)) != -1) { 
      data.appendData(readBuffer, 0, chunkSize); 
     } 
     mDelegate.receivedDataForRequest(request, data); 
    } 
} 

當它掛起它約30秒左右之後總是最終拋出一個TCP超時錯誤。 如果偶爾發生這種情況,我只會將它記錄爲正常的網絡擁塞,但它經常發生足以指示更深層的問題。

編輯:

它發生在各種模擬器和我有2個物理設備。 我曾嘗試是模擬器...

  • 風暴9550
  • 粗體9000
  • 明珠9100
  • 曲線8530

我有一個曲線8530和Storm 9550設備,它也發生在這兩者上。

任何幫助,將不勝感激。

+0

這是在模擬器或真實設備? – 2010-07-08 19:56:56

+0

添加設備和模擬器信息。 – 2010-07-08 21:01:54

+0

我問的原因是因爲我發現5.0模擬器在網絡仿真方面相當麻煩 - 通常掛起連接沒有明顯的原因。但是,既然你也在真實設備上看到它,它肯定是不同的。 – 2010-07-08 21:31:13

回答

0

在其他地方建議在我的網絡I/O線程中放置一個失速檢測器,並在檢測到失速時,中斷線程並重新啓動請求。我通過在開始請求之前啓動一個計時器並在讀取每個數據塊時重置計時器來實現這一點。如果計時器在我能夠讀取塊之前就已經過期,我假設網絡已經停止工作,並且我中斷了該線程並重新開始該請求。

我已經完成了這項工作,它至少減少了我必須等待的延遲,因爲我無需等待可能需要很長時間的TCP超時,才能繼續執行請求。

中斷當前的I/O操作並重新啓動似乎會使網絡恢復正常運行一段時間後,通常會繼續運行幾分鐘,然後再次停止運行。調試時,我將這些檔位記錄到控制檯,並且我獲得了相當多的信息。

這是一個非常奇怪的問題,我並不完全滿意失速檢測解決方案。這似乎只是掩蓋了這個問題,但它確實讓我有點解決了我得到的長時間延誤。

0

您可能想嘗試Available()方法。即使您在一個後臺線程上序列化數據,它看起來像請求是在主線程中創建的。你可能會遇到一些奇怪的競賽情況。

+0

我還以爲我可能會處理一個奇怪的競爭條件,但對於我的生活,我找不到一個。唯一的共享數據是請求隊列,並且在發佈線程和處理線程之間正確同步。 – 2010-07-09 14:56:46

0

您可以添加一些日誌記錄來顯示設備選擇用於每個連接的傳輸類型嗎?也許這是運輸選擇API挑選它認爲會起作用的運輸工具的情況,但事實上並非如此。

+0

每次它選擇TRANSPORT_TCP_CELLULAR。 – 2010-07-08 22:59:50

0

我認爲在我使用的所有BlackBerry操作系統上執行read(byte[], int, int)時存在一個錯誤 - 4.5至6.0。
我爲InputStream編寫了一個適配器,將read(byte[], int, int)變成一個調用read(),並解決了我正在處理的應用程序中的流掛問題。

如果你讀了RIM規範read(byte[], int, int)它說:

讀(B,關閉,LEN)類InputStream的方法簡單地調用read()將反覆的方法。如果第一次這樣的調用導致IOException,那麼從調用讀取(b,off,len)方法返回該異常。如果任何後續的read()調用導致IOException異常,則捕獲異常並將其視爲文件結尾;到此爲止讀取的字節將被存儲到b中,並返回發生異常之前讀取的字節數。鼓勵子類提供更高效的方法實現。

我按照這個規範編寫了我自己的版本,並遇到了同樣的問題。我相信問題是,一旦有數據可用,該方法需要返回而不會阻塞。要做到這一點的唯一方法是利用available()來查看可以不阻塞地讀取多少字節。由於RIM文檔沒有提及使用available(),我認爲它只是調用read(),直到緩衝區已滿或read()返回-1。如果您的數據以小爆發形式出現,這可能需要很長時間。如果該「長時間」超出連接超時,連接就會死亡。

這是我使用的代碼,它解決了懸掛連接問題:

public int read(byte[] bts, int st, int len) throws IOException { 
    if(len == 0) { 
     return 0; 
    } 
    int readByte = this.read(); 
    if(readByte == -1) { 
     return 0; 
    } 
    bts[st] = (byte)readByte; 
    return 1; 
}