3

我想开发一个基于 XML 并通过 TCP/IP 套接字传输的文本协议。假设我有一个简单的请求/响应机制,可以通过客户端和服务器之间的持久 TCP/IP 连接发送,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<request id="1" command="get.answer">
    <value type="string">Answer to the Ultimate Question of Life, the Universe, and Everything</value>
</request>

<?xml version="1.0" encoding="UTF-8"?>
<response id="1" command="get.answer">
    <value type="int32">42</value>
</response>

双方何时应该开始处理传入的数据,或者换句话说,服务器何时知道传入的客户端数据已完全传输并且可以处理以创建响应?

当然,我对该主题进行了一些研究:我发现这个答案基于 HTTP 示例指向了正确的方向:因此,在 XML 消息之上使用一种“传输协议”肯定会有所帮助。

但我还研究了纯粹基于 XML 的 XMPP 协议,至少据我所见,它不使用任何“传输协议”,如 HTTP。

从 RFC 6120 的“2.4。结构化数据”中读取:

XMPP 中的基本协议数据单元不是 XML 流(它只是提供点对点通信的传输),而是 XML“节”,它本质上是通过流发送的 XML 片段。节的根元素包括路由属性(例如“from”和“to”地址),而该节的子元素包含用于传递给预期接收者的有效负载。

所以他们基本上通过 TCP/IP 发送没有“传输协议”的小 XML 块,从我的 wireshark 跟踪中我可以看到,每个 XML 节的末尾也没有特殊的传输结束字符,比如两次 \r \n 或类似的东西。那么他们如何知道消息(节)的结尾呢?

4

4 回答 4

2

实际上,XMPP 使用XML 流来传输数据。您所指的数据单元是单个消息的实际交换,但它们都包含在 XML 流中,该流定义了 XMPP 会话的通信的开始和结束点。

这将是传输结束发生的地方,就像所有传输结束一样。在该流中,有 3 种已定义的数据包类型(IQ、消息和存在),它们将指示单个消息的开始和结束(用于客户端到服务器的通信)。

尽管基本情况是通过 TCP 连接完成的,但也有一些扩展来支持不同的有线协议,例如HTTP,它对于允许 XMPP 通过防火墙很有用。

如果您想做类似的事情,那么您可以采用相同的方法,即在建立和断开连接时开始和结束 XML 流。然后您只需要定义单独的消息类型,这样您的端点就会知道什么构成了完整的消息。

或者您可以只使用似乎非常适合您的用例的 XMPP。

于 2012-04-18T13:52:16.167 回答
0

正如@Robin 所说,XMPP 具有基于 XML 流的传输。它还可以使用 HTTP 作为BOSH的传输。

在第二种(HTTP)情况下,事情很简单。例如Strophe,一个使用 BOSH 的 js 库,请求本质是 HTTP 请求,因此具有Content-Length. 它看起来像这样:

POST /webclient HTTP/1.1
Content-Type: text/xml; charset=utf-8
Content-Length: 240

<body rid='1573741825'
      sid='SomeSID'
      xmlns='http://jabber.org/protocol/httpbind'>
  <iq id='bind_1'
      type='set'
      xmlns='jabber:client'>
    <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
      <resource>httpclient</resource>
    </bind>
  </iq>
</body>

在第一种情况下(XML 流),尽管情况有所不同。我使用的一个性能良好、存在已久且经过测试的 Python 库Twisted在Expat XML parser上使用了一个 Python 包装器。解析器是一个快速的、非验证的解析器,它会抛出有用的事件,例如指示“根”元素的开始或结束。然后将收到的元素一一解析。

于 2012-04-18T18:42:59.770 回答
0

XMPP 端点必须解析 XML。通过这样做,它知道什么时候结束,因为只允许有 1 个文档(顶级)元素(我不确定它们是否可能在 XML 处理器指令之前)

<?xml version="1.0" encoding="UTF-8"?>
<request id="1" command="get.answer">
    <value type="string">Answer to the Ultimate Question of Life, the Universe, and Everything</value>
</request>

这是自定界的,因为一旦您解析了<request标记,您就会知道该 XML 文档在您点击匹配时结束</request>

(就个人而言,我会在下面的协议级别放置一个框架协议,而不是将原始 xml 填充在(TCP)流之上,也许只是在每条消息之前使用一个 4 字节的大字节序长度字段。)

于 2012-04-19T10:14:00.447 回答
0

正如这里提到的,主要有两种方法:有一个分隔符或标题中的长度。您的分隔符可能只是您的开始标签的结尾,这就是 XMPP 正在做的事情。这意味着只要您的 XML 消息被包装在一个正确开始和结束的标签中,您就可以开始使用。如果您想对收到的数据块进行某种验证,您需要做的是确保所有标签都结束。大多数解析器包都会为您执行此操作。如果你向他们传递一个不可解析的包,他们会抛出一个异常。如果您想编写自己的解析器,那么您需要更多地研究解析器而不是传输/XML 协议。

于 2012-04-19T10:04:21.307 回答