2011-07-25 13 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があります。 次のメソッド(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型)

別スレッドにメソッドを配置する必要がありますか?これを何度も繰り返して、私の記憶モジュールを交換しても(私が奇妙なアイディアを持ち始めたとき)

...助けてください。

+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

私は誰からも応答の断片を使用することができました。私はavailable()呼び出しに頼るべきではありません。 APIでもそうだとは思いますが...私はそれを短くしようとしていました。 – sergio

1

ソケットからデータを読み取ることは非同期プロセスであり、パケット[]が完全に埋め込まれる前にsetPacketInfo()が呼び出されることはありますか?この場合、デバッグ時にはうまくいく可能性がありますが、実際には別のマシン上のソケットを使用するとひどい場合があります。

setPacketInfo()メソッドにコードを追加して、packet []変数の長さをチェックすることができます。

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

なぜあなたはパケット[]変数をpkt []にコピーするのですか?

+0

パケットのタイプを見るためにちょうど最初の2バイトをコピーしています。 – sergio

+0

パケットの長さは1001です。タイプは最初の2バイトです。 – 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); 

あなたはまた、BufferedInputStreamであなたのDataInputStreamをラップし、あなたがしようとしないように、あなたは以下の2つのバイトを取得する場合の世話をする必要があります受け取っていないバイトを処理します。 @eznmeからの回答に追加するには

0

。保留中のデータがなくなるまで、基本ストリームから読み込む必要があります。これは、1つ以上の読み出しを必要とすることができるが、使用可能方法は、私は、そのよりバイト[]配列を取得し、ByteArrayOutputStreamに「コピー」にApache IOUtilsを使用して入力ストリームを推薦する0を返す場合、ストリームの終わりが示されます。

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

バウンド例外のうちを取り除くでしょう、あなたが読んだとき、あなたが取得している:あなたはあなたのプロトコルヘッダのバイトを取得する前に、あなたのデータバッファ長のチェックを行う必要があり、あなたのsetPacketInfo方法で

あなたのプロトコルからの長さ0のデータバッファ