【问题标题】:Java sockets - how to determine data type on the server side?Java 套接字 - 如何确定服务器端的数据类型?
【发布时间】:2010-05-07 18:37:10
【问题描述】:

我将 Java 套接字用于客户端 - 服务器应用程序。我有一种情况,有时客户端需要发送一个字节数组(使用 byteArrayOutputStream),有时它应该发送一个自定义的 java 对象。如何从服务器端的输入流中读取信息并确定流中的内容以便正确处理?

【问题讨论】:

    标签: java networking sockets


    【解决方案1】:

    通常这是通过在正文前面发送一个包含有关正文的信息的“标题”来完成的。看看例如HTTP protocol。 HTTP 流存在一个由双换行符与正文分隔的标头。标题依次存在多个name: value 格式的字段,每个字段由一个换行符分隔。在这种特殊情况下,您将在 HTTP 中使用 Content-Type 标头来标识正文的数据类型。

    由于 Java 和 TCP/IP 没有为此提供标准工具,因此您需要详细指定并记录您将通过线路发送的格式,以便对方知道如何处理流。当然,您也可以获取标准规范。例如。 HTTP 或 FTP。

    【讨论】:

      【解决方案2】:

      有多种方法可以处理这个问题。

      一个是对象序列化,它使用 Java 的 Object(In|Out)putStream 发送它。但是,当您知道何时从流中读取对象时,您会遇到一个小问题。

      另一个是编组和解组 XML。使用更多流量,但更容易调试和运行。它有助于为此拥有一个有据可查的 XML 模式。这里的一个优点是您可以使用现有的 XML 库。

      如果需要,您可以尝试自定义格式,但它最终可能只是一个草率、不那么冗长的 XML 版本。

      【讨论】:

      • 这里的关键是作者绝不应该尝试实现自己的对象编组代码。
      • @Jason 我同意:我想不出任何你想要这样做的理由。
      【解决方案3】:

      一般来说,我认为 Java 中没有内置的功能可以让您做到这一点。

      相反,请考虑在每条消息中发送更多信息,说明接下来会出现什么类型。

      例如,您可以在消息前加上一个整数,这样每次收到消息时,您都会读取前 4 个字节(整数为 4 个字节)并解释其值(例如 1=字节数组,2=自定义 Java 对象,3=另一个自定义 Java 对象,...)。

      您还可以考虑添加一个包含消息大小的整数,以便知道当前消息何时结束以及下一条消息何时开始。

      【讨论】:

      • 如果你打算做一个消息开始/结束标志,那么还可以编写一个转义协议特别有帮助,这样如果你变得不同步,你可以只寻找消息开始标记。如果消息开始字节出现在代码中的任何位置,则将其转换为两个字节的转义序列。您还可以转义转义字符本身,以及您想要避免的任何其他字节(例如,在 RS-232 上使用时,^S 和 ^Q)。
      • 我不建议使用开始/结束标志,因为在序列化 Java 类时,您可能会在尝试序列化 Java 类时发现任何字符(^S、^Q、\0 等)。我建议包括消息的长度以及消息的类型。虽然,发布者可能已经根据 Java 对象的类型知道这一点(也许对象将始终具有完全相同的字段)。
      • 您进行转义是为了确保您的协议是完全二进制安全的,尽管您有特殊的开始/结束标记字节(可能还有您想要完全避免的字节)。如果两个端点不同步,长度字节并不能帮助您恢复,但诚然,这可能不是您通过 TCP 连接担心的事情。
      【解决方案4】:

      我会被要求为此矫枉过正,但除非你真的需要这个协议是经济的,否则你可能会考虑编组数据。我的意思是,如果不查看数据,您通常无法区分字节数组和其他内容之间的区别,因为您可以想象将所有内容表示为字节数组。

      您可以很容易地使用 JAXB 将数据编组到 XML 和从 XML 中提取。 JAXB 甚至会为您将字节数组对象转换为十六进制字符串或 Base64。

      【讨论】:

        【解决方案5】:

        首先将数据读入服务器上的字节数组。编写您自己的解析例程,仅识别字节数组中的内容。

        第二次根据第一步中的标识执行完整的对象解析。如果解析需要传递一个输入流,您可以随时将您在第一步中读取的字节数组放入一个新的 ByteArrayInputStream 实例中。

        【讨论】:

          【解决方案6】:

          您需要定义一个协议来指示遵循什么类型的数据。例如,您可以使用字符串或枚举值开始每次传输。服务器会先读取这个,然后根据 'header' 值读取以下数据。

          【讨论】:

            【解决方案7】:

            您可以做的是在您发送的任何数据前面加上一个用于确定类型的整数。

            这样,您可以读取前 4 个字节,然后确定它是什么类型的数据。

            【讨论】:

              【解决方案8】:

              我认为最简单的方法是使用包含您将发送的数据及其类型信息的对象。然后你可以发送这个对象,根据这个对象的数据类型属性,你可以提取数据。

              【讨论】:

                猜你喜欢
                • 2012-06-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-02-25
                • 2012-06-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多