【问题标题】:java.net.Socket > outputStream > BufferedOutputStream flush() confirmationjava.net.Socket > outputStream > BufferedOutputStream flush() 确认
【发布时间】:2015-03-09 13:08:28
【问题描述】:

有没有办法知道 BufferedOutputStream 线程的 flush() 方法何时或是否成功完成?在我的例子中,我使用它通过 java.net.Socket 发送一个简单的字符串。在下面的代码中,flush() 方法与 BufferedReader.read() 方法并行运行,并且套接字输出立即被输入读取阻塞,从而导致类似于死锁的情况。我想做的是等待输出结束,然后开始读取输入。

Socket sk = new Socket("192.168.0.112", 3000);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write(message.getBytes());
bo.flush();

BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
String line = br.readLine();
if (line.equals("ack")) {
    System.out.println("ack");
}


sk.close();

更新

服务器套接字:

ServerSocket ss = new ServerSocket(3000);
        System.out.println("server socket open");
        while (true) {
            Socket sk = ss.accept();
            System.out.println("new connection");
            BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
            String line = br.readLine();
            System.out.println("received line: " + line);
            BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
            bo.write("ack".getBytes()); bo.flush();
            sk.close();
        }

更新

@Global 变量 - read 阻塞套接字的原因是它确实在等待 \n。使用

bo.write("ack\n".getBytes());

而不是

bo.write("ack".getBytes());

成功了。

关于最初的问题,有没有办法知道 flush() 方法是否成功完成,@Stephen C 提供了答案:

没有办法知道基于 Socket 或 OutputStream API。 获得这种保证的正常方法是使用遥控器 应用程序发送一个“回复”作为响应,并在本地读取它 一边。

此“回复”已在代码示例中实现,并且有效。

【问题讨论】:

    标签: java sockets tcp


    【解决方案1】:

    有没有办法知道BufferedOutputStream线程的flush()方法何时或是否成功完成?

    这取决于您所说的“成功完成”。

    flush() 方法确保管道中所有未发送的数据都已推送到操作系统网络堆栈。完成后,您可以说flush() 已成功完成。您知道发生这种情况的方式是 flush() 调用返回。

    另一方面,如果你想确保数据已经(全部)传送到远程机器,或者远程应用程序已经读取它(全部)......没有办法知道基于Socket 或 OutputStream API。获得这种保证的正常方法是让远程应用程序发送一个“回复”作为响应,并在本地读取它。


    在以下代码中,flush() 方法与 BufferedReader.read() 方法并行运行,并且套接字输出立即被输入读取阻塞,从而导致类似于死锁的情况。

    您所说的代码基本上是正确的方法。等待响应的方法就是这样读。

    如果不工作,那么你需要比较一下客户端和服务器端在做什么:

    • 服务器是否在等待客户端发送更多内容?也许是行尾?

    • 服务器发送响应了吗?

    • 回复flush()了吗?

    客户端和服务器之间的不匹配可能导致表单或死锁,但解决方案是修复不匹配。等待flush() 的某种假设确认不是答案。

    更新

    问题确实是不匹配。例如,服务器写入"ack",但客户端需要"ack\n"。同样的情况发生在客户端 -> 服务器案例中......除非message 总是以换行符结尾。

    【讨论】:

    • 嗨斯蒂芬,我的目的是检查是否在服务器端收到消息。我的目标序列是这样的: (1) 客户端发送消息 (2) 服务器接收消息 (3) 服务器发送 ACK (4) 客户端接收 ACK 问题是,在实现 Socket 时,监听输入阻塞了输出​​线程。而且,即使我希望输出同步运行,它也不会。 (1) 和 (4) 并行处理。我想做的是在套接字不再忙于处理步骤(1)之后运行(4)。
    • 向我们展示服务器端代码。 “问题在于,在实现 Socket 时,侦听输入会阻塞输出线程。” - 这不是真的。
    • 我已经添加了 ServerSocket 部分。
    • 我已经测试过了,这个过程没有完成步骤(1)。步骤 (2) .. (4) 也不运行。
    【解决方案2】:

    您的代码正在读取 reader.readLine() 。你在写的时候写\n吗?您可能希望将 \n 附加到您正在编写的字符串中。

    【讨论】:

    • 好的,这是一个想法,但是 reader.readLine() 的替代方案是什么?我以前用过它,它在没有 \n 的情况下工作。
    • 您可以使用 inputstream.read()。但随后您将不得不将自己的消息边界协商为特殊字节或字符(以便能够区分一条消息和另一条消息)
    • 如果套接字 inputStream 没有监听消息,一切正常(服务器接收到消息,有或没有行尾)。发生套接字死锁是因为写入和读取是并行线程,由上面的代码触发。我认为输出的优先级低于输入;在这种情况下,如果消息尚未发送,则无法收到 ACK。
    • 我的意思是 read() 和 flush() 方法。它们触发共享资源的 IO 线程 - 客户端套接字。
    • "ObjectInputStream 构造函数阻塞,直到它完成读取序列化流标头。在为该流创建相应的 ObjectOutputStream 之前等待构造 ObjectInputStream 的代码将死锁,因为 ObjectInputStream 构造函数将阻塞,直到header 被写入流,直到 ObjectOutputStream 构造函数执行后才会将 header 写入流。这个问题可以通过在 ObjectInputStream 之前创建 ObjectOutputStream 来解决,[...]。"
    【解决方案3】:

    我试图重现您的问题。首先,我也遇到了某种阻塞状态,直到我意识到,我也在服务器端使用readLine。但是我发送的消息没有结论\n。因此,服务器套接字仍在其InputStream 处等待,而没有通过其OutputStream 向客户端发送ACK。我认为,@Global Variable 是对的。

    【讨论】:

      猜你喜欢
      • 2019-09-17
      • 1970-01-01
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 2016-06-12
      • 1970-01-01
      • 2010-11-28
      相关资源
      最近更新 更多