线路协议
此页面描述了用于开发其他语言(如 C# 或 C 本机客户端)的客户端的逻辑 OpenWire 协议。请注意,OpenWire 旨在实现最大性能和功能;它是 ActiveMQ Classic 内部使用的协议。如果您想使用更简单的协议来开始使用跨语言客户端,请尝试使用 Stomp,该协议旨在简化实现,因此易于支持许多客户端。
协议概述
ActiveMQ Classic 的客户端将交换命令对象(遵循命令模式)。我们将描述这些命令是如何交换的……
该协议主要使用单向消息传递(发布并忘记)来处理大多数类型的命令 - 但在某些情况下会使用 RPC(请求、响应)消息传递。我们将清楚地指出 RPC 场景。
建立连接
客户端必须发送一个 ConnectionInfo 命令,其中包含机器、主机名、用户名、密码以及最重要的客户端希望使用的唯一 clientId 的详细信息,然后等待有效响应才能继续。clientId 必须使用唯一的字符串生成器生成。
发送消息
建立连接后,您需要创建一个逻辑 MessageProducer。这涉及发送一个 ProducerInfo 命令,其中包含唯一的 producerId、sessionId 和 clientId(连接 ID)。
从那时起,您可以在任何时候发送 Message 命令,前提是您用 clientId、sessionId、producerId 以及必要时的 transactionId(请参阅下面的事务)来装饰该消息。
消费消息
命令将传递到您的入站套接字以供消费。其中一些将是先前 RPC 的响应,其余将是传入的消息以供调度。
要开始消费消息,您必须发送一个 ConsumerInfo 命令,其中包含 clientId、sessionId 和唯一的 consumerId 的详细信息。从那时起,您将收到包含它们目标 consumerId 的传入消息。
要确认一条消息,请向服务器发送一个 MessageAck(单向)。使用 consumerId、sessionId、clientId 和任何 transactionId 的详细信息填充 MessageAck。
使用响应
当您创建连接、生产者和消费者时,您将收到一个响应以指示请求的状态(例如是否成功或失败)。由于该协议是异步的,因此您可以以乱序接收 Response 命令;您可以在多个线程中使用同一个连接/套接字并行发送命令。
因此,在多线程客户端中,通常会使用某种相关映射将命令 ID 与响应 ID 匹配,以便您可以知道哪个线程中的哪个操作成功或失败等。请参阅 Java 中的传输实现,了解我们是如何做到的。例如,请参阅 ResponseCorrelator
ID
目前,客户端需要自动生成客户端、会话、生产者和消费者 ID,这些 ID 通常是字符串,旨在全局唯一。同样,每个命令都有自己的整数计数器 ID,用于客户端将请求与响应关联;客户端通常会为此使用递增的滚动计数器。
关闭生产者、消费者、会话、连接
要关闭资源,请发送一个 RemoveInfo 命令,其中包含生产者、消费者、会话、连接等的正确 objectId。
JMS 事务
每个事务会话都会生成一个唯一的 transaction ID,该 ID 会传递到任何事务消息中。要开始、提交或回滚,客户端应发送一个 TransactionInfo 命令(单向)(不会生成响应)。
提交或回滚后,应生成新的 transaction ID 并发送新的开始 TransactionInfo。
发送的任何消息或进行的消息确认也应传播 transaction Id。
XA 事务
如上所述,但使用 XATransactionInfo。我们还传递 XAid 而不是 transactionID。
最后的想法
如果您对协议的一部分有疑问,最简单的方法是检查 JMS 客户端代码。特别是查看 ActiveMQSession 的代码,其中包含几乎所有上述逻辑。特别注意在将命令发送到消息代理时对syncSendCommand() 和asyncSendCommand() 的调用。