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

时间:2017-01-04 10:53:24

标签: java multithreading sockets network-programming

我有两个应用程序在两个不同的服务器上运行。 一个应用程序通过套接字连接连接到另一个应用程序,并通过该套接字发送数据。接收应用程序读取该数据并对其执行某些操作。 发送应用程序使用下一段代码来执行此操作:

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

full_packet是一个字节数组,其维度为size * 53int2ByteArray()方法如下所示:

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

基本上,我在发送实际数据之前发送数据包的大小。

接收应用程序使用下一段代码读取数据:

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等于53. byteArray2Int()方法如下:

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

in的类型为DataInputStream

问题现在开始了。当我在笔记本电脑上运行这两个应用程序时,一切都很好,所有数据都通过它的发送方式来实现。我运行发送应用程序的几个线程,发送几种大小的数据流。 但是,当在服务器上运行它时,如果数据很大,它就不会按原样运行。 如果我试图发送长度为5300字节的数据包,那么它很好。如果我发送长度为15900字节甚至更大的数据包,在某些时候读取应用程序不能正确读取数据包,并且下次读取大小的4个字节时,它会收到一些奇怪的数字并且它会阻塞应用程序。 当我尝试运行多个线程时会发生同样的事情,每个线程都会发送不同大小的不同数据。

有人能指出这个过程中的问题吗?我该如何解决?有什么建议? 任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:0)

InputStream并不总是读取到达字节数组的所有字节。当数据包足够小时,底层的InputStream实现可能会返回整个数据包,但是,如果它变大,就像在以后的实验中一样,它可能无法读取它们,因为它的缓冲区不能保持@ycesar提到的大部分数据。一种方法是增加缓冲区大小,但它只是隐藏了问题。要真正解决问题,您需要检查InputStream.read()的返回值是否与预期的数据包大小相匹配。

在apache commons-io中有一些方便的方法,如IOUtils.read()。只要遵循许可证,您就可以使用它或根据自己的目的进行修改。它看起来像这样:

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

以上代码是从https://github.com/apache/commons-io/blob/2.5/src/main/java/org/apache/commons/io/IOUtils.java#L2901下获得许可的Apache 2.0复制而来的。没有修改。

答案 1 :(得分:0)

您忽略read()返回的计数。实现这一目标的最简单方法是DataInputStream.readFully()

答案 2 :(得分:-1)

我不确定但是默认套接字接收缓冲可能低于预期。为什么不尝试使用setReceiveBufferSize()函数来增加此接收缓冲区大小?

希望它对你有所帮助。