【问题标题】:Designing a network protocol for realtime data / mobile devices为实时数据/移动设备设计网络协议
【发布时间】:2011-01-06 00:42:35
【问题描述】:

我面临以下两难境地:

设计一种用于服务器(Java 软件)与桌面和移动客户端之间的新网络协议。移动客户端包括 J2ME、Android,未来可能甚至包括 iPhone。

数据流是实时的、恒定的流,也包含更多不常见的部分。客户端显示此数据的波形以及不需要立即更新的数据。客户端也应该经过身份验证。

如果可能,我想避免从头开始创建完全自定义的 TCP 协议实现。

现在人们通常建议以我也非常喜欢的 REST 风格来做所有事情。在这种情况下,我有点犹豫:您将如何在 REST 之上实现恒定的数据流?分块的 HTTP 响应?

我也在考虑非明文协议(我要替换的当前协议是二进制协议)。那些当前的协议有相当严重的问题,所以它们真的应该被替换。

Google 协议缓冲区看起来是处理低级细节的一个非常强大的候选者,但我不确定它是否可以在 Android 中使用。而且我很确定 iPhone 的实现也会有问题。

还有BEEP,但我认为它已经死了,我想知道它是否曾经被广泛使用。

有什么想法吗?

【问题讨论】:

    标签: java tcp network-protocols


    【解决方案1】:

    我认为在开始协议设计之前,您应该认真考虑以下问题:

    • 如今,除了 HTTP 之外,几乎所有协议都被防火墙过滤。 甚至许多内容类型和端口(80 除外)也可能被服务提供商过滤,尤其是在移动数据服务中。因此,在选择使用或设计协议之前,请确保您的目标网络中没有防火墙问题。
    • 大小和速度很重要。尝试在传输消息大小和编码/解码(序列化/反序列化)速度方面使用高效的协议。 Google Protocol Buffers 为这个问题提供了可靠的解决方案。
    • 连接总是断开连接。 由于 NAT 超时(默认为 15 分钟)、协议超时(TCP 为 30 分钟)和许多现有的网络问题,您永远不能依赖连接保持打开状态。所以,不要仅仅因为它保持连接打开而更喜欢另一个协议(它可能会尝试,但永远不会成功)。发送心跳是解决超时问题的一个很好的尝试,但网络断开仍然是不可避免的。
    • 吞吐量很重要。吞吐量是指在一段时间内(例如 1 秒)处理的消息数。使用在收到消息后断开客户端的异步协议,确实有助于提高吞吐量。尽管不依赖从服务器连接到客户端来推送结果,因为许多客户端位于 NAT 和防火墙后面,避免了来自外部的直接连接。尝试保持连接打开或轮询服务器以获取结果。避免对话中的状态也是另一种有助于随着客户端数量的增长而扩展应用程序吞吐量的方法。
    • 现有的广域网没有实时性。不要相信那些说他们已经实现了基于现有广域网协议的实时协议的人。您永远无法在非实时协议之上实现实时协议。您可以尽力而为,并祈祷网络快速运行。这意味着:不要停下来,尽力而为。
    • Non-Blocking IO。 NIO(Non-blocking IO)是现在的趋势,有效地用于网络编程。它可以使用更少的内存和有限的线程数实现大量连接。 Java 5 原生支持非常原始的 NIO。许多框架,例如Apache MINANetty,都基于Java NIO实现,使非阻塞编程更简单、更健壮。我强烈推荐他们。

    【讨论】:

    • 谢谢!我不知道有广泛使用的 Java 替代 NIO 框架。我曾经针对 Java NIO API 进行编程,但有时我仍然会在夜里尖叫起来(它一定是 Sun 生产过的最糟糕的 API):-) 这个新信息让 NIO 再次与我相关!
    • 我完全同意你的看法。在基于 Java NIO API 进行开发时,我也做过同样的噩梦 :-) Apache MINA 永远改变了我的生活。
    【解决方案2】:

    您可能会查看Kryo 和/或KryoNet,它们基于 NIO 和 Java,可在桌面和 Android 上运行。不过,您必须编写 iPhone 端,这将相当棘手。 Kryo 在序列化大小 (benchmarks here) 和易用性方面胜过 Google 的 Protocol Buffers(无需编写 .proto 类型的架构,使用 Kryo,Java 类定义就是架构)。

    关于蔚来,您可以查看NPTL。旧的又变成了新的。

    【讨论】:

      【解决方案3】:

      您可能想查看RTP (Real-time Transport Protocol),它可能没有直接用处(和/或可能是矫枉过正),但它的设计会给您一些好主意。而且你很可能会使用它。

      【讨论】:

        【解决方案4】:

        这不是一个优雅的解决方案,但您可以通过直接 http 执行此操作,方法是不在 http 响应上设置 content-length 字段,并且永远不要关闭输出流。继续发送数据。

        你也可以设置一个非常大的content-length,并从服务器实时发回数据,直到服务器发送了这个数量,然后客户端可以选择是否发出新的请求。

        很遗憾,我找不到这些想法的任何有用链接,但我相信您能理解这些想法。

        这些想法的真正优点是它们通过 http 解决了防火墙问题,并且您可以将您的应用程序实现为带有 servlet 的 web 应用程序。

        只要我的 2 美分 ;)

        【讨论】:

        • 谢谢。实际上,我正在替换的当前协议之一是 - 在高层次上 - 几乎是这样,但有一个区别:http响应基本上是无限的。我不确定 content-length 标头的内容是什么,或者是否以某种方式被省略了。无论如何,它的当前形式存在问题。似乎所有的防火墙都不喜欢无休止的 http 响应,但我只看到了让我陷入这个假设的症状。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-14
        • 2012-12-13
        • 1970-01-01
        • 2012-09-26
        相关资源
        最近更新 更多