在具有未定义字节数的SocketChannel上通过TCP读取流

时间:2014-03-12 23:48:51

标签: java network-programming nio socketchannel

我试图在没有定义字节数的情况下读取SocketChannel上的流。

我想到的替代解决方案是将预定义大小的不同ByteBuffers存储到一个列表中,这将允许我之后分配一个接收大小的新ByteBuffer并将结果放入其中。

问题是我处于阻塞模式并且找不到有效条件离开我在read方法上做的循环检查代码:

public static final Charset charsetUTF8 = Charset.forName("UTF-8");
public static final int BUFFER_SIZE = 1024;

public static String getUnbounded(String st, SocketAddress address) throws IOException {
    SocketChannel sc = SocketChannel.open(address);
    sc.write(charsetUTF8.encode(st));
    List<ByteBuffer> listBuffers = new ArrayList<>();
    ByteBuffer buff = ByteBuffer.allocate(BUFFER_SIZE);
    while( sc.read(buff) > -1){
        if(buff.remaining() == 0){
            listBuffers.add(buff);  
            buff.clear();
        }
    }

    listBuffers.add(buff);
    ByteBuffer finalBuffer = ByteBuffer.allocate(BUFFER_SIZE * listBuffers.size());
    for(ByteBuffer tempBuff: listBuffers){
    finalBuffer.put(tempBuff);
        tempBuff.clear();
    }
    finalBuffer.flip();

    return charsetUTF8.decode(finalBuffer).toString();
}

关于如何解决这个问题的任何想法?

3 个答案:

答案 0 :(得分:2)

你不能只是clear()字节缓冲区。你需要分配一个新的;否则,相同的缓冲区将重复添加到listBuffers

ByteBuffer buff = ByteBuffer.allocate(BUFFER_SIZE);
while( sc.read(buff) > -1){
    if(buff.remaining() == 0){
        listBuffers.add(buff);  
        buff = ByteBuffer.allocate(BUFFER_SIZE);
    }
}
if (buff.position() > 0) {
    listBuffers.add(buff);
}

由于最后一个缓冲区可能(可能不会)已满,因此您应该考虑到这一点来计算finalBuffer大小。

答案 1 :(得分:0)

HTTP响应流中的字节数不是“未定义”。请参阅RFC。它由以下任一定义:

  1. 关闭连接时的EOS(HTTP 1.0或连接:关闭),
  2. Content-Length标头,或
  3. 解码分块编码格式的结果。
  4. 必须以其中一种方式定义它,并且可能还有其他方式,以便HTTP持久连接可以工作,在此之后可能会有另一个响应。

    我想知道为什么你实现这个,当HttpURLConnection类已经存在时,以及各种第三方HTTP客户端,它们已经正确地实现了所有这些,还有很多其他的东西。< / p>

答案 2 :(得分:-1)

解决方案是离开循环我不得不打电话:

sc.shutdownOutput();

关闭写入流而不关闭读取流并将sc.read(buff)设置为-1