如何在java中识别InputStream的结尾

Var*_*man 37 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");
Run Code Online (Sandbox Code Playgroud)

我得到输出: -

,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
Run Code Online (Sandbox Code Playgroud)

但没有输出: - 循环结束

请指导我如何关闭循环?

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

Jon*_*eet 49

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

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

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

我个人赞成尽可能使用长度前缀; 它使阅读代码显着简化,但仍然允许同一连接上的多个消息.

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

  • @Vardhaman:虽然不仅仅是*TCP.涉及更高级别的协议,它描述了消息的格式,控制流等.您应该询问"他们"预期的行为是什么. (2认同)
  • @ ikzjfr0:嗯,我不会仔细研究代码来理解如何.TCP/IP是基于流的协议; 任何超过*的*都要考虑到它.现在它上面的一个库可以为你做消息长度前缀*,但这并没有消除它的需要......它只是为你做.那些是非常不同的. (2认同)

Ste*_*n C 17

我想你实际上回答了自己的问题.

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

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

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


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


Pet*_*rey 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();
Run Code Online (Sandbox Code Playgroud)

版画

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.
Run Code Online (Sandbox Code Playgroud)


Nis*_*han -4

您可以在循环后安全地关闭流whiledataInt-1 意味着没有更多内容可供读取。

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

如果 while 循环没有退出,则意味着流的另一端仍有数据正在写入。关闭另一端的流。如果您可以在将数据写入流的位置发布代码,那将会很有帮助。

  • 我认为你误解了这个问题...... dataInt 永远不会是-1。 (4认同)
  • @Heiko Rupp:不,语义是相同的。当到达流的末尾时,读取将返回 -1。时期。 (2认同)