如何在java中识别InputStream的结尾

时间:2011-04-06 06:40:28

标签: java sockets inputstream

我正在尝试使用Socket程序从服务器读取字节,即我使用InputStream来读取字节。如果我传递长度大小,我能够读取字节,但我不确定长度是多少。所以我无法初始化字节数组。

我也试过while (in.read() != -1),我发现它在发送数据时循环工作正常,但循环后的下一行不可执行,我觉得它仍然在寻找流中的数据但是没有数据。如果我关闭服务器连接,那么我的客户端将执行下一行,然后循环。

我不确定我哪里出错了?

this.in = socket.getInputStream();

int dataInt = this.in.read();

while(dataInt != -1){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}

System.out.print("End Of loop");

我得到的输出为: -

,1--0,2--62,3--96,4--131,5--142,6--1,7--133,8--2,9--16,10--48,11--56,12--1,13--0,14--14,15--128,16--0,17--0,18--0,19--48,20--0,21--0,22--0,23--0,24--0,25--1,26--0,27--0,28--38,29--114,30--23,31--20,32--70,33--3,34--20,35--1,36--133,37--48,38--51,39--49,40--52,41--49,42--55,43--49,44--52,45--52,46--54,47--55,48--50,49--51,50--52,51--48,52--53,53--56,54--51,55--48,56--48,57--57,58--57,59--57,60--57,61--57,62--57,63--57,64--56

但没有输出: - 循环结束

请指导我如何关闭循环?

期待您的回复。提前感谢你们。

8 个答案:

答案 0 :(得分:47)

它正在寻找更多数据,因为没有人告诉它不会更多的数据。网络的另一端可以随时发送更多数据。

目前尚不清楚您是在设计客户端/服务器协议还是只是尝试实现它,但通常有三种常见的方法来检测消息的结束:

  • 关闭邮件末尾的连接
  • 将消息的长度放在数据本身之前
  • 使用分隔符;一些永远不会出现在正常数据中的值(或者总会以某种方式转义)

我个人赞成在可能的情况下使用长度前缀;它使阅读代码显着简化,但仍允许在同一连接上发送多条消息。

(另外,我同意Daniel的观点,你应该使用read的重载,它一次读取整个缓冲区,而不是单个字节。这样会更有效 - 但不是从根本上改变当前问题的性质。)

答案 1 :(得分:17)

我认为你实际上回答了自己的问题。

您不退出循环的原因是输入流的结尾仅在服务器端关闭其套接字后发生在客户端。 (或者更确切地说,在它关闭其套接字输出流......或等效的......之后,close事件已传播到客户端。)

在该事件发生之前,服务器可能决定将更多数据写入套接字。所以客户端读取阻塞......直到它获得更多数据或者它看到协议事件表明服务器端已经关闭。

(实际上,其他事件可以取消阻止客户端读取,但它们都会导致某种类型的IOException,并且可能是您无法再读取任何数据的流。)


现在,如果您现在不想关闭服务器端,因为您希望稍后在套接字上发送更多内容,则必须更改应用程序协议以使用某种框架机制。例如,服务器可能发送一个帧(或记录,或其他),包括字节计数,后跟给定的字节数。或者,它可以使用区分字节值或字节序列来标记帧的结尾。

答案 2 :(得分:5)

您可以运行此示例。

如果您要等待流的结束,则必须在发送方关闭它并接收EOF(-1)。

对于发送多个二进制消息,我更喜欢在消息之前发送长度,因为它允许代码一次读取大块(即因为它知道它将获得多少)

ServerSocket ss = new ServerSocket(0);
Socket s = new Socket("localhost", ss.getLocalPort());
Socket s2 = ss.accept();

final OutputStream out = s.getOutputStream();
out.write("Hello World!".getBytes());
out.close();

final InputStream in = s2.getInputStream();
for (int b = 0; ((b = in.read()) >= 0);) {
    System.out.println(b + " " + (char) b);
}
System.out.println("End of stream.");
s.close();
s2.close();
ss.close();

打印

72 H
101 e
108 l
108 l
111 o
32  
87 W
111 o
114 r
108 l
100 d
33 !
End of stream.

答案 3 :(得分:0)

对于一次TCP连接,这对我有用:

ByteArrayOutputStream buffer = new ByteArrayOutputStream();
InputStream input = socket.getInputStream();
final byteSize = 1024;
byte[] data = new byte[byteSize];
int nRead;
while ((nRead = input.read(data, 0, data.length)) != -1) {
    buffer.write(data, 0, nRead);
    if (nRead < byteSize) {
        break;
    }
}
buffer.flush();
byte[] byteArray = buffer.toByteArray();

供参考,该内容改编自Java InputStream to Byte Array and ByteBuffer

答案 4 :(得分:-1)

我遇到过类似的问题,其中in.read()只是挂在数据末尾而不是返回-1。

如果您无法控制服务器代码,是否有可靠的标记,您可以在返回的数据中检测到(例如</html>)并使用它来结束读取循环?

如果不这样做,请考虑使用socket.setSoTimeout(reasonableValue),因此至少您的应用不会永远悬空......

答案 5 :(得分:-2)

在-1的情况下,它不会结束循环。将65535置于该状态,我99%确定它将停止循环。

while(dataInt != 65535){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}

答案 6 :(得分:-3)

您可以在while循环后安全地关闭流。 dataInt为-1表示没有其他内容可供阅读。

http://download.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html#read()

如果while循环没有退出,则意味着仍然在流的另一端写入数据。关闭另一端的流。 如果您可以在您将数据写入流的代码中发布有用的代码。

答案 7 :(得分:-3)

我还有一个问题,就是我没有走出循环。我的解决方案与此类似:

while (in.ready()){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}