【发布时间】:2010-05-07 18:37:10
【问题描述】:
我将 Java 套接字用于客户端 - 服务器应用程序。我有一种情况,有时客户端需要发送一个字节数组(使用 byteArrayOutputStream),有时它应该发送一个自定义的 java 对象。如何从服务器端的输入流中读取信息并确定流中的内容以便正确处理?
【问题讨论】:
标签: java networking sockets
我将 Java 套接字用于客户端 - 服务器应用程序。我有一种情况,有时客户端需要发送一个字节数组(使用 byteArrayOutputStream),有时它应该发送一个自定义的 java 对象。如何从服务器端的输入流中读取信息并确定流中的内容以便正确处理?
【问题讨论】:
标签: java networking sockets
通常这是通过在正文前面发送一个包含有关正文的信息的“标题”来完成的。看看例如HTTP protocol。 HTTP 流存在一个由双换行符与正文分隔的标头。标题依次存在多个name: value 格式的字段,每个字段由一个换行符分隔。在这种特殊情况下,您将在 HTTP 中使用 Content-Type 标头来标识正文的数据类型。
由于 Java 和 TCP/IP 没有为此提供标准工具,因此您需要详细指定并记录您将通过线路发送的格式,以便对方知道如何处理流。当然,您也可以获取标准规范。例如。 HTTP 或 FTP。
【讨论】:
有多种方法可以处理这个问题。
一个是对象序列化,它使用 Java 的 Object(In|Out)putStream 发送它。但是,当您知道何时从流中读取对象时,您会遇到一个小问题。
另一个是编组和解组 XML。使用更多流量,但更容易调试和运行。它有助于为此拥有一个有据可查的 XML 模式。这里的一个优点是您可以使用现有的 XML 库。
如果需要,您可以尝试自定义格式,但它最终可能只是一个草率、不那么冗长的 XML 版本。
【讨论】:
一般来说,我认为 Java 中没有内置的功能可以让您做到这一点。
相反,请考虑在每条消息中发送更多信息,说明接下来会出现什么类型。
例如,您可以在消息前加上一个整数,这样每次收到消息时,您都会读取前 4 个字节(整数为 4 个字节)并解释其值(例如 1=字节数组,2=自定义 Java 对象,3=另一个自定义 Java 对象,...)。
您还可以考虑添加一个包含消息大小的整数,以便知道当前消息何时结束以及下一条消息何时开始。
【讨论】:
我会被要求为此矫枉过正,但除非你真的需要这个协议是经济的,否则你可能会考虑编组数据。我的意思是,如果不查看数据,您通常无法区分字节数组和其他内容之间的区别,因为您可以想象将所有内容表示为字节数组。
您可以很容易地使用 JAXB 将数据编组到 XML 和从 XML 中提取。 JAXB 甚至会为您将字节数组对象转换为十六进制字符串或 Base64。
【讨论】:
首先将数据读入服务器上的字节数组。编写您自己的解析例程,仅识别字节数组中的内容。
第二次根据第一步中的标识执行完整的对象解析。如果解析需要传递一个输入流,您可以随时将您在第一步中读取的字节数组放入一个新的 ByteArrayInputStream 实例中。
【讨论】:
您需要定义一个协议来指示遵循什么类型的数据。例如,您可以使用字符串或枚举值开始每次传输。服务器会先读取这个,然后根据 'header' 值读取以下数据。
【讨论】:
您可以做的是在您发送的任何数据前面加上一个用于确定类型的整数。
这样,您可以读取前 4 个字节,然后确定它是什么类型的数据。
【讨论】:
我认为最简单的方法是使用包含您将发送的数据及其类型信息的对象。然后你可以发送这个对象,根据这个对象的数据类型属性,你可以提取数据。
【讨论】: