1

am having this very strange problem: i have a small program that reads bytes off a socket; whenever i am debugging, the program runs fine; but every time i run it (like straight up run it), i get the ArrayIndexOutOfBounds exception. what gives? am i reading it too fast for the socket? am i missing something?

here is the main():

public static void main(String[] args){

    TParser p = new TParser();

    p.init();

    p.readPacket(); 

    p.sendResponse();

    p.readPacket();

    p.sendResponse();

    p.shutdown();

}

The method init is where i create the Sockets for reading and writing; The next method (readPacket) is where problems start to arise; i read the entire buffer to a private byte array so i can manipulate the data freely; for instance, depending on some bytes on the data i set some properties:

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();

    }
}

The line where it breaks is the line

pkt[1]= packet[1]; (setPacketInfo)

meaning it only has 1 byte at that time... but how can that be, if whe i debug it it runs perfectly? is there some sanity check i must do on the socket? (dataIN is of type DataInputStream)

should i put methods on separate threads? ive gone over this over and over, even replaced my memory modules (when i started having weird ideas on this)

...please help me.

1
  • Have you tried printing out available? Are you sure it's 1? Also, wrt the memory module, you'll nearly always be safe assuming it's your problem rather than the compiler/hw. It's nice to think but almost never the case. Commented Jul 25, 2011 at 13:45

5 Answers 5

4

I dont know the surrounding code, especially the class of dataIN but I think your code does this:

int available=dataIN.available(); does not wait for data at all, just returns that there are 0 bytes available

so your array is of size 0 and you then do:

pkt[0]= packet[0]; pkt[1]= packet[1]; which is out of bounds.

I would recommend that you at least loop until the available() returns the 2 you expect, but i cannot be sure that that is the correct (* ) or right (** ) way to do it because i dont know dataIN's class-implementation.

Notes: (* ) it is not correct if it is possible for available() to e.g. return the 2 bytes separately. (** ) it is not the right way to do it if dataIN itself provides methods that wait.

Sign up to request clarification or add additional context in comments.

1 Comment

ill try this. it seems i have some synchronization of sorts to do, but this will do for the moment
1

Can it be that reading the data from the socket is an asynchronous process and the setPacketInfo() is called before your packet[] is completely filled? If this is the case, it's possible it runs great when debugging, but terrible when it really uses sockets on different machines.

You can add some code to the setPacketInfo() method to check the length of the packet[] variable.

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

not really sure though why you even copy the packet[] variable into pkt[]?

2 Comments

am copying just the first 2 bytes to see the type of the packet.
the packet has a length of 1001. the type is in the first two bytes.
0

You are using a packet oriented protocol on a stream oriented layer without transmitting the real packet length. because of fragmentation the size of received data can be smaller than the packet you sent.

Therefore I strongly recommend to send the data packet size before sending the actual packet. On the receiver side you could use a DataInputStream and use blocking read for detecting an incoming packet:

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();
    }
}

Of course you have to modify the sender side as well, sending the packet size before the packet.

1 Comment

i was able to use fragments of responses from everybody, thanks. i should not rely on the available() call. i believe even the API says that...but i was trying to cut it short.
0

To add to the answer from @eznme. You need to read from your underlying stream until there is no more pending data. This may required one or more reads, but an end of stream will be indicated when the available method returns 0. I would recommend using Apache IOUtils to 'copy' the input stream to a ByteArrayOutputStream, then getting the byte[] array from that.

In your setPacketInfo method you should do a check on your data buffer length before getting your protocol header bytes:

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

That will get rid of the out of bound exceptions you are getting when you read zero-length data buffers from your protocol.

Comments

0

You should never rely on dataIN.available(), and dataIN.read(packet,0,available); returns an integer that says how many bytes you received. That's not always the same value as what available says, and it can also be less than the size of the buffer.

This is how you should read:

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

You should also wrap your DataInputStream in a BufferedInputStream, and take care of the case where you get less than 2 bytes, so that you don't try to process bytes that you haven't received.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.