2011-07-25 53 views
1

我有這個非常奇怪的問題:我有一個小程序,從套接字讀取字節;每當我調試時,程序運行正常;但每次我運行它(就像直接運行它),我得到ArrayIndexOutOfBounds異常。是什麼賦予了?我是否對插口讀取速度太快?我錯過了什麼?從一個Java套接字讀取字節:獲取ArrayIndexOutOfBounds

這裏是主():

public static void main(String[] args){ 

    TParser p = new TParser(); 

    p.init(); 

    p.readPacket(); 

    p.sendResponse(); 

    p.readPacket(); 

    p.sendResponse(); 

    p.shutdown(); 

} 

方法INIT是其中i創建用於讀取和寫入的套接字; 下一個方法(readPacket)是問題開始出現的地方;我讀整個緩衝區到一個私人字節數組,所以我可以自由操縱數據;例如,根據在所述數據部分字節我設置一些屬性:

public void readPacket(){  

    System.out.println("readPacket"); 
    readInternalPacket(); 
    setPacketInfo(); 
} 

private void readInternalPacket(){ 
    System.out.println("readInternalPacket"); 
    try {   
     int available=dataIN.available();   
     packet= new byte[available];  
     dataIN.read(packet,0,available); 

     dataPacketSize=available; 

    } 
    catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 


private void setPacketInfo() { 

    System.out.println("setPacketInfo"); 
    System.out.println("packetLen: " +dataPacketSize); 

    byte[] pkt= new byte[2]; 
    pkt[0]= packet[0]; 
    pkt[1]= packet[1]; 

    String type= toHex(pkt); 
    System.out.println("packet type: "+type); 
    if(type.equalsIgnoreCase("000F")){ 
     recordCount=0; 
     packetIterator=0; 
     packetType=Constants.PacketType.ACKPacket; 
     readIMEI(); 
     validateDevice(); 

    } 
} 

其中它打破是直線的線

PKT [1] =包[1]; (setPacketInfo)

這意味着它只有1個字節在那個時間......但如何能,如果我調試它運行完美?有一些理智的檢查,我必須做的插座? (dataIN是DataInputStream類型)

我應該把方法放在單獨的線程上嗎? ive一遍又一遍地遍歷了這個,甚至更換了我的記憶模塊(當我開始對此有奇怪的想法時)

...請幫助我。

+0

您是否嘗試過打印出可用的?你確定它是1嗎?另外,對於內存模塊,假設它是你的問題,而不是編譯器/ hw,你幾乎總是安全的。很高興思考,但幾乎從未如此。 –

+0

現在試圖.... – sergio

回答

0

您正在面向流的層上使用面向數據包的協議,而不傳輸實際的數據包長度。由於分段,接收數據的大小可能比發送的數據包小。

因此,我強烈建議在發送實際數據包之前發送數據包大小。在接收器側,你可以使用一個DataInputStream和使用阻塞讀取用於檢測輸入分組:

private void readInternalPacket() { 
    System.out.println("readInternalPacket"); 
    try { 
     int packetSize = dataIN.readInt(); 
     packet = new byte[packetSize]; 
     dataIN.read(packet, 0, packetSize); 
     dataPacketSize = packetSize; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

當然必須修改發送器側以及,數據包之前發送所述分組的大小。

+0

我能夠使用每個人的反應片段,謝謝。我不應該依賴可用的()調用。我相信甚至API也會這樣說......但我試圖把它縮短。 – sergio

1

是否可以從套接字讀取數據是一個異步過程,並且在packet []被完全填充之前調用setPacketInfo()?如果是這樣的話,它可能在調試時運行得很好,但當它真的在不同的機器上使用套接字時可能會很糟糕。

您可以將一些代碼添加到setPacketInfo()方法來檢查packet []變量的長度。

byte[] pkt= new byte[packet.length]; 
for(int x = 0; x < packet.length; x++) 
{ 
     pkt[x]= packet[x]; 
} 

不確定爲什麼你甚至將packet []變量複製到pkt []中?

+0

上午只是複製只有前2個字節看到數據包的類型。 – sergio

+0

數據包的長度爲1001.該類型位於前兩個字節中。 – sergio

4

我不知道周圍的代碼,尤其是類dataIN但我覺得你的代碼做這個:

int available=dataIN.available();沒有等待的任何數據,只是返回有可用0字節

所以您的陣列的大小爲0,然後執行以下操作:

pkt[0]= packet[0]; pkt[1]= packet[1];這是超出範圍的。

我會建議你至少循環,直到available()返回你所期望的2,但我不能確信這是正確的(*)或右(**)的方式來做到這一點,因爲我不知道dataIN「實施課程。

備註:(*)如果available()可能與分別返回2個字節。 (**)如果dataIN本身提供等待的方法,則不是正確的方法。

+0

虐待這個。似乎我有一些同步做的事情,但這會做的 – sergio

0

您不應該依賴dataIN.available(),並且dataIN.read(packet,0,available);會返回一個整數,表示您接收到了多少個字節。這並不總是與可用的值相同,也可能小於緩衝區的大小。

這是你應該如何閱讀:

byte[] packet = new byte[1024]; // 
dataPacketSize = dataIN.read(packet,0,packet.length); 

你也應該換你DataInputStreamBufferedInputStream,並採取你在哪裏得到少於2個字節的情況下照顧,所以不要嘗試處理你還沒有收到的字節。

0

添加到@eznme的答案。您需要從您的基礎流讀取,直到沒有更多未決數據。這可能需要一個或多個讀取,但當方法返回0時,會顯示流結束。我建議使用Apache IOUtils將輸入流「複製」爲ByteArrayOutputStream,然後從該數組中獲取byte []數組。

在你setPacketInfo方法,你應該做你的數據緩衝區長度的檢查讓你的協議頭字節之前:

byte[] pkt= new byte[2]; 
if((packet != null) && (packet.length >= 2)) { 
    pkt[0]= packet[0]; 
    pkt[1]= packet[1]; 
    // ... 
} 

這將擺脫了束縛的例外,當你閱讀你所得到來自您協議的零長度數據緩衝區。