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

Java 在SocketChannel上通过TCP读取未定义字节数的流,java,network-programming,nio,socketchannel,Java,Network Programming,Nio,Socketchannel,我试图在SocketChannel上读取流,而不定义字节数 我考虑的另一种解决方案是将不同的预定义大小的字节缓冲存储到一个列表中,这样以后我就可以根据接收到的大小分配一个新的字节缓冲,并将结果放入其中 问题是我处于阻塞模式,无法找到有效条件来离开我在read方法上进行的循环检查代码: public static final Charset charsetUTF8 = Charset.forName("UTF-8"); public static final int BUFFER_SIZE = 1

我试图在SocketChannel上读取流,而不定义字节数

我考虑的另一种解决方案是将不同的预定义大小的字节缓冲存储到一个列表中,这样以后我就可以根据接收到的大小分配一个新的字节缓冲,并将结果放入其中

问题是我处于阻塞模式,无法找到有效条件来离开我在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();
}
公共静态最终字符集charsetUTF8=Charset.forName(“UTF-8”);
公共静态最终整数缓冲区大小=1024;
公共静态字符串getUnbounded(字符串st,SocketAddress地址)引发IOException{
SocketChannel sc=SocketChannel.open(地址);
sc.write(charsetUTF8.encode(st));
List listBuffers=新的ArrayList();
ByteBuffer buff=ByteBuffer.allocate(缓冲区大小);
而(sc.read(buff)>-1){
如果(buff.remaining()==0){
添加(buff);
buff.clear();
}
}
添加(buff);
ByteBuffer finalBuffer=ByteBuffer.allocate(BUFFER_SIZE*listBuffers.SIZE());
用于(ByteBuffer tempBuff:listBuffers){
最终缓冲区放置(临时缓冲区);
tempBuff.clear();
}
finalBuffer.flip();
返回charsetUTF8.decode(finalBuffer.toString();
}
有没有办法解决这个问题

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

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
大小。

HTTP响应流中的字节数不是“未定义的”。看。其定义如下:

  • EOS在连接关闭的情况下(HTTP 1.0或连接:关闭)
  • 内容长度标题,或
  • 对分块编码格式进行解码的结果
  • 必须用这些方法中的一种来定义它,也许还有其他方法,以便HTTP持久连接可以工作,在这种情况下可能会有另一个响应


    我想知道,当
    HttpURLConnection
    类已经存在,以及各种第三方HTTP客户机(它们已经正确地实现了所有这些)以及其他许多东西时,您为什么要实现这一点。

    解决方案是,为了摆脱循环,我必须调用:

    sc.shutdownOutput();
    

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

    clear()方法在存储ByteBuffer后清除ByteBuffer,然后read()方法放入新字节inside@Hosni-是的,但每次都要将相同的
    ByteBuffer
    对象添加到
    listBuffers
    。最后,无论循环退出时处于何种状态,它都将充满相同的
    buff
    。对于
    listBuffers
    的每个元素,您都需要一个单独的对象。但是由于我已经在循环外部声明并创建了一个ByteBuffer,所以我不能在循环内部创建另一个具有相同标识符的ByteBufferit@Hosni是的,你可以。这叫做“分配声明”。@Hosni-你看到了什么行为?当您尝试我的代码时,行为是否发生了变化?为什么您觉得需要使用
    ByteBuffer
    ?有什么建议吗?加上read方法只需要byteBuffer为什么要使用通道?您正在阻塞IO,并将数据存储到堆分配的缓冲区中。你真的认为通过一个简单的
    SocketInputStream
    ?或
    HttpURLConnection
    ?@kdgregory我需要通道,因为我以后需要使用选择器,因为这是一个http流的示例,但我无法将其全部用于streams@Hosni我回答了你问的问题。在编辑之前,您说过您正在使用HTTP流。你现在问的是一个完全不同的问题。HTTP流有不同于其他流的定义字节数的方法。根据您当前的代码,TCP流只能读取到EOS。另一个应用程序协议可能会在每条消息之前发送长度,或者使用类型长度值、XDR、XML等编码。没有一个通用的解决方案。这不是您最初提出的问题的解决方案。您还没有明确说明需要在发送方调用
    shutdownOutput()
    -1我不知道我需要关闭写入流,我只需要一个方法,该方法允许我离开循环并将read()方法设置为-1,我在问题中说了。问题是,你根本不应该在read()方法中:你应该知道HTTP响应中有多少字节。@EJP,但这不是HTTP请求