Java 使用套接字时“流结束”是什么意思

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/649320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 17:23:14  来源:igfitidea点击:

What does 'end of stream' mean when working with sockets

javasocketsnetwork-programming

提问by Mystic

When working with Sockets in Java, how can you tell whether the client has finished sending all (binary) data, before you could start processing them. Consider for example:

在 Java 中使用套接字时,如何在开始处理它们之前判断客户端是否已完成发送所有(二进制)数据。考虑例如:

istream = new BufferedInputStream (socket.getInputStream());
ostream = new BufferedOutputStream(socket.getOutputStream());

byte[] buffer = new byte[BUFFER_SIZE];

int count;
while(istream.available() > 0 && (count = istream.read(buffer)) != -1)
{
    // do something..
}

// assuming all input has been read
ostream.write(getResponse());       
ostream.flush();

I've read similar posts on SO such as this, but couldn't find a conclusive answer. While my solution above works, my understanding is that you can never really tell if the client has finished sending all data. If for instance the client socket sends a few chunks of data and then blocks waiting for data from another data source before it could send more data, the code above may very well assume that the client has finished sending all data since istream.available() will return 0 for the currentstream of bytes.

我对SO如阅读类似的帖子这个,也没有找到确凿的答案。虽然我的上述解决方案有效,但我的理解是您永远无法真正判断客户端是否已完成发送所有数据。例如,如果客户端套接字发送了一些数据块,然后在它可以发送更多数据之前阻塞等待来自另一个数据源的数据,则上面的代码很可能假设客户端已完成自 istream.available() 以来的所有数据发送将为当前的字节流返回 0 。

回答by Nick Borodulin

I think this is the task more of a protocol, assuming that you are the man who writes both the transmitting and receiving sides of application. For example you could implement some simple logic protocol and divide you data into packets. Then divide packets into two parts: the head and the body. And then to say that your head consists of a predefined starting sequence and contains number of bytes in the body. Of forget about starting sequence and simpy transfer number of bytes in the bofy as a first byte of the packet. Then you've could solve you problem.

我认为这更像是一个协议的任务,假设您是编写应用程序发送端和接收端的人。例如,您可以实现一些简单的逻辑协议并将数据划分为数据包。然后将数据包分成两部分:头部和主体。然后说你的头部由一个预定义的起始序列组成,并包含正文中的字节数。忘记作为数据包的第一个字节的 bofy 中的起始序列和简单传输字节数。那你就可以解决你的问题了。

回答by serioys sam

as Nikitasaid this is more of task of protocol. Either you can go by header and body approach or you can send a special character or symbol for end of stream to break processing loop. Something like if you send say '[[END]]' on socket to denote end of stream.

正如Nikita所说,这更多是协议的任务。您可以通过标题和正文方法进行操作,也可以发送特殊字符或符号作为流结束符以中断处理循环。就像你在套接字上发送说 '[[END]]' 来表示流结束一样。

回答by Jon Skeet

Yes, you're right - using available()like this is unreliable. Personally I very rarely use available(). If you want to read until you reach the end of the stream(as per the question title), keep calling read()until it returns -1. That's the easy bit. The hard bit is if you don't want the end of the stream, but the end of "what the server wants to send you at the moment."

是的,你是对的 -available()像这样使用是不可靠的。我个人很少使用available(). 如果您想阅读直到到达的末尾(根据问题标题),请继续调用read()直到它返回 -1。这是容易的一点。难点是如果您不想要流的结尾,而是“服务器目前想要发送给您的内容”的结尾。

As the others have said, if you need to have a conversation over a socket, you mustmake the protocol explain where the data finishes. Personally I prefer the "length prefix" solution to the "end of message token" solution where it's possible - it generally makes the reading code a lot simpler. However, it can make the writingcode harder, as you need to work out the length before you send anything. This is a pain if you could be sending a lot of data.

正如其他人所说,如果您需要通过套接字进行对话,则必须让协议解释数据在哪里结束。就个人而言,我更喜欢“长度前缀”解决方案,而不是“消息结束标记”解决方案,它通常使阅读代码更简单。但是,它会使编写代码变得更加困难,因为您需要在发送任何内容之前计算出长度。如果您要发送大量数据,这会很痛苦。

Of course, you can mix and match solutions - in particular, if your protocol deals with both text and binary data, I would stronglyrecommend length-prefixing strings rather than null-terminating them (or anything similar). Decoding string data tends to be a lot easier if you can pass the decoder a complete array of bytes and just get a string back - you don't need to worry about reading to half way through a character, for example. You could use this as part of your protocol but still have overall "records" (or whatever you're transmitting) with an "end of data" record to let the reader process the data and respond.

当然,您可以混合和匹配解决方案 - 特别是,如果您的协议处理文本和二进制数据,我强烈建议使用长度前缀字符串而不是空终止它们(或任何类似的东西)。如果您可以将完整的字节数组传递给解码器并返回一个字符串,那么解码字符串数据往往会容易得多 - 例如,您无需担心读取到一半的字符。您可以将其用作协议的一部分,但仍然具有带有“数据结束”记录的整体“记录”(或您正在传输的任何内容),以让阅读器处理数据并做出响应。

Of course, all of this protocol design stuff is moot if you're not in control of the protocol :(

当然,如果您无法控制协议,那么所有这些协议设计内容都没有实际意义:(

回答by voyager

As some ppl already said you can't avoid some kind of protocol for communication. It should look like this for example:

正如某些人已经说过的那样,您无法避免某种通信协议。例如,它应该如下所示:

On the server side you have:

在服务器端,您有:

 void sendMSG(PrintWriter out){
    try {
        //just for example..
        Process p = Runtime.getRuntime().exec("cmd /c dir C:");
        BufferedReader br = new BufferedReader(new InputStreamReader(
            p.getInputStream()));

        //and then send all this crap to the client
        String s = "";
        while ((s = br.readLine()) != null) {
          out.println("MSG");
          out.println(s);
        }
      } catch (Exception e) {
        System.out.println("Command incorrect!");
      }
      out.println("END");
}
//You are not supposed to close the stream or the socket, because you might want to send smth else later..

On the client side you have:

在客户端,您有:

void recieveMSG(BufferedReader in) {
    try {
      while (in.readLine().equals("MSG")) {
        System.out.println(in.readLine());
      }
    } catch (IOException e) {
      System.out.println("Connection closed!");
    }
  }