【问题标题】:make sure `response.getOutputStream().write()` was received确保收到`response.getOutputStream().write()`
【发布时间】:2012-08-06 13:39:30
【问题描述】:

我以以下方式编写对 HTTP 请求的响应: response.getOutputStream().write()

我想确保客户收到它。

这一定是可能的,因为 TCP 会发送确认。

这个要求还意味着写入必须是一个阻塞操作(这对我来说很好!)。

那么我怎么知道它是否按照上述方式完成(我怀疑不是)?有什么规范可以保证吗? 有什么方法可以实现吗?我使用的是 Tomcat 6。

... PS,我的意思是 除了 让客户端在另一个 HTTP 请求中发送此确认 :)

【问题讨论】:

    标签: java http networking tcp


    【解决方案1】:

    首先,您可以确保刷新输出流缓冲区:

    response.getOutputStream().flush();
    

    它保证数据真正被发送出去。 TCP 将确保它到达,否则会给您的服务器一个错误,该错误将转换为 IOException。

    简而言之,如果您可以写入并且没有出错,那么您的客户端确实收到了数据。至少在 TCP 堆栈上。客户端显然负责消费消息。

    TCP 提供数据完整性和传递保证。它将继续重传,直到接收方确认接收到数据包。但这一切都发生在 TCP 堆栈内部。您的代码可以假设它发生了,或者您收到了错误。只有这两种情况是可能的。

    此外,您可能希望确保关闭输出流,否则您的客户端可能会坐在那里缓冲数据,直到它接收到流的结尾。

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      你确定这是你想要的吗?测试写入是否成功? TCP 旨在确保其正常工作,如果数据包失败,您将开始断开连接和 IOExeceptions。事实上,你会得到 RunTimeException。这样做的方法是将响应发送回源。并等待响应到来。

      等的时候,保证等了一定时间就放弃了,这样才不会挂。

      假设您只想调试代码。如果你想调试使用像 ethereal 这样的数据包嗅探器。相信我,一旦你的逻辑正确,你就不需要 ack 数据包了。

      【讨论】:

      • 如果一个数据包失败,你可能在 TCP 检测到它之前很久就关闭了连接,你肯定不会得到RuntimeException。投反对票。
      • 从一个奇怪的问题开始。 TCP 比 UDP 更好地传送数据包。知道它是否收到好的唯一方法是发回一个 ack。 TCP 本身发送 ACK,因此实际上没有必要。在极少数情况下,TCP 连接坏了它会抛出一个 RunTimeException。
      • @Siddarth 一切都是正确的,但您忽略了 TCP 写入是异步的。写入不会等到 ACK 返回:它只是将数据缓冲到内核中的套接字发送缓冲区中。因此,除非错误条件已经存在于先前的 I/O 中,否则它没有任何理由抛出 IOException ,这将需要几秒钟的时间。因此,您不能仅仅依靠写入中没有 IOExceptions 来表示写入已被确认。它没有。您提到的 RuntimeException 是您的想象。
      • 我想说的是,测试写入不是必需的。为什么已建立的协议(如 TCP)会提供同步选项。异步是它最擅长的(正如您正确指出的那样)。 Java 将所有套接字问题抽象为 2 个异常 IOException 和 RunTimeException。
      • 我想解释一下我的“想象”。当客户端关闭连接/退出时会引发 RunTimeException。如果您正在编写需要为多个客户端提供服务的服务器,则需要抓住这一点,并将其视为“clientClosedConnection”并继续为其他客户端提供服务。即使 ioObjectStream 写入调用不会抛出这种异常,java 服务器总是会捕获这种异常。请注意,我不会冒昧攻击你,只是因为我们不同意。
      【解决方案3】:

      TCP 只知道数据已经被对端接收。它不知道对等应用程序 已收到数据。并且 TCP 写入是异步的,因此在写入或刷新返回到发送应用程序后很长时间才能检测到错误。

      应用程序可以通过另一个 HTTP 事务确认接收,但 HTTP 应该是无状态的,这样做会违反该规则。

      我建议你查一下“两军问题”。

      您应该做的是让您的交易幂等(查找)然后确保交易发生是客户的责任。如果客户没有得到响应,他应该只是重复交易。对重试次数设置一个下限,比如两次或三次。

      【讨论】:

      • +1 好答案!但是,您说 HTTP is supposed to be statelessnot get the response he should merely repeat the transaction 会与自己发生冲突,因为,如果不发出另一个 HTTP 请求,我将如何获得响应(我假设您的意思是“服务器”而不是“客户端”)。
      • 除此之外,谁说“HTTP 应该是 ..”.. 无论如何都有“会话”等使其有状态......就像不是一样。
      • 所以基本上你建议,为了使这个消息传递系统(这正是它的本质)具有幂等性,我最好将其处理移至客户端,同时使其也明确地确认接收到消息,对吗?
      • @Poni (1) 通过发出另一个请求,您会得到另一个响应。 (2) HTTP RFC 将其定义为无状态协议。 (3) 如果事务是幂等的,则不需要确认响应的到达。
      • @Downvoters 请解释您对上述问题的看法。无法解释的反对票对任何人都没有帮助,只会引起其他怀疑。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-04
      • 2022-08-31
      • 1970-01-01
      相关资源
      最近更新 更多