简体   繁体   English

从套接字读取的字节数组不一致

[英]inconsistent byte array read from socket

I have two applications running on two different servers. 我有两个运行在两个不同服务器上的应用程序。 One application connects to the other one by socket connection and through that socket it sends data. 一个应用程序通过套接字连接连接到另一个应用程序,并通过该套接字发送数据。 The receiving application reads that data and does something with it. 接收应用程序读取该数据并对其进行处理。 The sending application uses the next piece of code to do it: 发送应用程序使用下一段代码来执行此操作:

out.write(int2ByteArray(size));
out.flush();
Thread.sleep(5);
out.write(full_packet);
out.flush();

full_packet is a byte array with the dimension of size * 53 and int2ByteArray() method looks like this : full_packet是一个字节数组,其大小为size * 53int2ByteArray()方法如下所示:

private static  byte[] int2ByteArray(int myInt){
    return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(myInt).array();
}

So basically, I send the size of my data packet before I send the actual data. 因此,基本上,我先发送数据包的大小,然后再发送实际数据。

The receiving application reads the data using the next piece of code: 接收应用程序使用下一段代码读取数据:

while (running){
    long startTime = System.currentTimeMillis();
    // read input data
    byte[] first_drop = new byte[4];
    in.read(first_drop);
    int size = byteArray2Int(first_drop);
    byte[] packet  = new byte [size * packet_size];
    Thread.sleep(5);
    in.read(packet);

    // do some thing with packet

    // go to sleep
    long endTime = System.currentTimeMillis();
    Thread.sleep(1000 - (endTime-startTime));
 }

packet_size equal 53. byteArray2Int() method looks like this: packet_size等于byteArray2Int()方法如下所示:

private int byteArray2Int(byte[] bArr){
        return ByteBuffer.wrap(bArr).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }

in is of type DataInputStream . in的类型为DataInputStream

The problem starts now. 问题现在开始。 When I run both applications on my laptop everything is fine and all data comes through the way it was sent. 当我在笔记本电脑上运行两个应用程序时,一切都很好,所有数据都通过发送方式来传递。 I run several threads of the sending application, sending several sizes of data streams. 我运行发送应用程序的多个线程,发送多个大小的数据流。 However, when run it on the servers, if the data is to big it does not come through as it should. 但是,在服务器上运行数据时,如果数据过大,将无法正常传输数据。 If I am trying to send packets that are 5300 bytes long then it is fine. 如果我尝试发送5300字节长的数据包,那很好。 If I am sending packets that are 15900 bytes long and even bigger, at some point the reading application does not read the data packet properly and the next time it reads the 4 bytes of the size it receives some weird number and it jams the application. 如果我发送的数据包长15900字节甚至更大,则在某些时候读取应用程序无法正确读取数据包,而在下次读取4字节大小的数据包时,它将收到一些奇怪的数字,从而阻塞了应用程序。 Same thing happens when I try to run several threads, each one send different data with a different size. 当我尝试运行多个线程时,同样的事情也会发生,每个线程发送不同大小的不同数据。

Can anyone point out the problem in the process? 谁能指出这个过程中的问题吗? How can I fix it? 我该如何解决? Any suggestions? 有什么建议么? Any help would be appreciated. 任何帮助,将不胜感激。

InputStream doesn't always read all bytes arrived into your byte array. InputStream并不总是读取到达字节数组的所有字节。 When the packet is small enough, the underlying InputStream implementation may return the whole packet, but, if it grows larger, as in your later experiments, it may not read them in a whole because its buffer can't hold that much of data, as mentioned by @ycesar. 当数据包足够小时,底层的InputStream实现可能会返回整个数据包,但是,如果数据包变得更大(如稍后的实验中所示),则可能无法整体读取它们,因为其缓冲区无法容纳那么多数据,如@ycesar所述。 One way is to increase buffer size, but it is just hiding the problem. 一种方法是增加缓冲区大小,但这只是隐藏问题。 To really solve the problem, you need to check if the return value of InputStream.read() match the expected packet size. 为了真正解决问题,您需要检查InputStream.read()的返回值是否与预期的数据包大小匹配。

There are convenience methods like IOUtils.read() in apache commons-io. apache commons-io中有IOUtils.read()这样的便捷方法。 You can make use of it or modify it for your own purpose as long as the license is followed. 您可以使用它,也可以根据自己的目的对其进行修改,只要遵循许可证。 It looks like this: 看起来像这样:

public static final int EOF = -1;

public static int read(final InputStream input, final byte[] buffer, final int offset, final int length)
        throws IOException {
    if (length < 0) {
        throw new IllegalArgumentException("Length must not be negative: " + length);
    }
    int remaining = length;
    while (remaining > 0) {
        final int location = length - remaining;
        final int count = input.read(buffer, offset + location, remaining);
        if (EOF == count) { // EOF
            break;
        }
        remaining -= count;
    }
    return length - remaining;
}

Above code is copied from https://github.com/apache/commons-io/blob/2.5/src/main/java/org/apache/commons/io/IOUtils.java#L2901 licensed under Apache 2.0 . 上面的代码是从Apache 2.0许可的https://github.com/apache/commons-io/blob/2.5/src/main/java/org/apache/commons/io/IOUtils.java#L2901复制而来的。 No modifications. 没有修改。

You're ignoring the count returned by read() . 您将忽略read()返回的计数。 The simplest way to accomplish this is wih DataInputStream.readFully() . 最简单的方法是wih DataInputStream.readFully()

I am not sure but maybe the default socket receive bufer is below expectations. 我不确定,但是默认套接字接收缓冲区可能低于预期。 Why don't you try with setReceiveBufferSize() function to increase this receive buffer size? 为什么不尝试使用setReceiveBufferSize()函数来增加此接收缓冲区的大小?

Hope it helps you. 希望对您有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM