2011-07-25 109 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]; 
    // ... 
} 

这将摆脱了束缚的例外,当你阅读你所得到来自您协议的零长度数据缓冲区。