【问题标题】:Socket communication with unknown input length输入长度未知的套接字通信
【发布时间】:2013-05-31 19:15:13
【问题描述】:

我正在尝试修复 java 套接字通信错误,其中服务器不知道输入消息的长度。在当前情况下,服务器测试输入是否使用inputStream.available(); 方法完成。然而,这种方法并不总是返回正确的答案。它会导致读取部分输入。解决这个问题似乎有两种不同的可能性。

  1. 客户端应发送输入大小。

  2. 客户端应该在发送后关闭它的输出流,但它会导致客户端无法读取响应,因为当输出流关闭时套接字也关闭了。

还有其他建议吗,尤其是在 nio 包的帮助下?

谢谢。

【问题讨论】:

    标签: java sockets client-server


    【解决方案1】:

    你可以使用

    socket.shutdownOutput();
    

    关闭客户端的输出流。这将显示为一个关闭的输入流,而不关闭套接字。

    顺便说一句:你不能像我一样使用socket.getOuputStream().close();

    恕我直言,发送长度是最好的选择,因为这将允许您使用同一个套接字发送多个请求。


    这是一个例子

    public class SimpleServerMain {
        public static void main(String... args) throws IOException, InterruptedException {
            ServerSocket ss = new ServerSocket(54321);
            Socket s = ss.accept();
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            for (String line; (line = br.readLine()) != null; )
                System.out.println("Got " + line);
    
            PrintStream ps = new PrintStream(s.getOutputStream());
            for (String word : "Hello World Bye Bye!".split(" ")) {
                ps.println(word);
                Thread.sleep(1000);
            }
            s.close();
            ss.close();
        }
    }
    

    public class SimpleClientMain {
        public static void main(String... args) throws IOException {
            Socket s = new Socket("localhost", 54321);
            InputStream inputStream = s.getInputStream();
    
            s.getOutputStream().write("Hello\n".getBytes());
            s.shutdownOutput();
    
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            for (String line; (line = br.readLine()) != null; )
                System.out.println("Got " + line);
            System.out.println("Disconnected.");
            s.close();
        }
    }
    

    【讨论】:

    • 感谢您的快速响应,我已尝试在客户端关闭输入流,但这也会导致连接关闭。因此,在关闭输入流后,客户端无法读取响应,因为套接字已关闭。
    • 关闭输出流并不一定要关闭连接,但有些库可能会这样做。如果他们这样做了,恕我直言,这是一个错误。直到一端关闭套接字才会关闭。如果您使用的库在您不知情的情况下关闭了套接字,我建议您使用另一个库。
    • 我正在使用 IBM jdk 的标准 java api。我认为这是默认行为。但我会尝试 socket.shutdownInput()。这是链接。stackoverflow.com/questions/3956163/…
    • 但是你说socket.getOutputStream().close()关闭socket?
    • 是的,当客户端写入其输出流并关闭它,然后当它尝试读取响应时,它会收到套接字关闭异常。
    【解决方案2】:

    available() 不是消息长度的度量,因此如果您对“正确答案”的定义是“消息长度”,它没有理由返回“正确答案”。

    如果你想要一个消息长度,你必须发送一个。或者使用行,或者像 XML、序列化等自描述协议。

    【讨论】:

      【解决方案3】:

      至少还有两种其他方法未提及,但可能应该提及。

      1. 使用特殊字符来表示某个输入的结束。如果输入中不允许有新行,则可以选择 \r\n

      2. 使用某种序列化 - 您可以将数据作为 JSON 对象或 XML 左右发送,然后您会知道什么时候没有更多数据。

      【讨论】:

        【解决方案4】:

        Imo,发送输入大小似乎是处理此问题的最佳方法,但您也可以尝试为每条消息定义固定的消息长度和 ID。

        您只需按照您选择的大小将消息分成几部分。
        收到新消息时,您只需检查 id 是否与前一个相同。如果是,则将新消息附加到第一条消息的末尾。如果不是,您可以对上一条消息执行您想要执行的操作,然后开始录制新消息。
        并且每次发送消息的所有部分时,客户端都会发送一条特殊消息来表示它已完成。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-03-11
          • 1970-01-01
          • 2020-07-07
          • 1970-01-01
          • 2021-12-04
          相关资源
          最近更新 更多