如何取消Smack发送的服务器能力探测请求(disco#info)
我完全理解你的场景:你固定和同一服务器通信,已经明确知晓它支持的服务能力,不需要Smack自动发送这些disco#info请求——尤其是那些在认证回调触发前就发出的请求。
先把你监测到的请求示例整理出来:
<iq to='muclight.server.com' from='id@server.com/R' id='yN82u-18' type='get'><query xmlns='http://jabber.org/protocol/disco#info'></query></iq> <iq to='pubsub.serve.com' from='id@server/R' id='yN82u-20' type='get'><query xmlns='http://jabber.org/protocol/disco#info'></query></iq> <iq to='upload.server.com' from='id@server/R' id='yN82u-24' type='get'><query xmlns='http://jabber.org/protocol/disco#info'></query></iq> <iq to='vjud.server.com' from='id@server/R' id='yN82u-22' type='get'><query xmlns='http://jabber.org/protocol/disco#info'></query></iq>
这些请求是Smack默认的自动服务发现机制触发的,尤其是在初始化MucLight、PubSub等服务管理器时,Smack会主动查询服务的能力。下面是几个可行的解决方案:
1. 禁用全局自动服务发现
Smack的ServiceDiscoveryManager是处理所有disco相关逻辑的核心类,你可以直接关闭自动发现服务的功能:
// 获取当前连接的ServiceDiscoveryManager实例 ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(yourXmppConnection); // 禁用自动发现远程服务 sdm.setAutoDiscoverServices(false);
这个方法会阻止Smack主动向服务器上的各个服务发送disco#info请求,但要注意:如果你的代码中有其他依赖自动发现的逻辑,可能需要手动适配。
2. 手动注入已知服务的能力信息
如果你不想完全禁用自动发现,而是针对特定服务提前注入已知的能力,Smack就不会再发送请求去查询这些服务:
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(yourXmppConnection); // 针对muclight服务注入信息 Jid mucLightJid = JidCreate.from("muclight.server.com"); sdm.addFeature(mucLightJid, "urn:xmpp:muclight:0"); // 添加服务支持的特性 sdm.addIdentity(mucLightJid, "conference", "muclight"); // 添加服务身份标识 // 针对pubsub服务注入信息 Jid pubSubJid = JidCreate.from("pubsub.server.com"); sdm.addFeature(pubSubJid, "http://jabber.org/protocol/pubsub"); sdm.addIdentity(pubSubJid, "pubsub", "publish-subscribe"); // 同理,为upload、vjud等服务添加对应的特性和身份
这样当Smack需要检查这些服务的能力时,会直接使用你预先注入的信息,无需发送请求。
3. 延迟初始化服务管理器到认证完成后
你提到请求是在连接管理器的auth回调触发前发出的,这通常是因为你在连接建立初期就初始化了MucLightManager、PubSubManager等实例。
解决方法很简单:将这些服务管理器的初始化代码移到认证成功的回调中,确保只有在认证完成后才创建这些实例,这样Smack就不会提前发送disco请求了。
示例代码:
yourXmppConnection.addConnectionListener(new ConnectionListener() { @Override public void authenticated(XMPPConnection connection, boolean resumed) { // 认证成功后才初始化服务管理器 MucLightManager mucLightManager = MucLightManager.getInstanceFor(connection, JidCreate.from("muclight.server.com")); PubSubManager pubSubManager = PubSubManager.getInstanceFor(connection, JidCreate.from("pubsub.server.com")); // 后续业务逻辑 } // 其他回调方法... });
4. 针对特定服务管理器禁用发现
部分Smack服务管理器提供了直接跳过disco发现的配置(取决于Smack版本),比如PubSubManager可以通过构造方法直接指定服务JID,并且不需要自动发现:
// 直接指定pubsub服务的JID,跳过自动发现 PubSubManager pubSubManager = new PubSubManager(yourXmppConnection, JidCreate.from("pubsub.server.com")); // 如果版本支持,可调用相关方法禁用发现 // pubSubManager.setDiscoveryEnabled(false);
你可以查看对应服务管理器的API文档,确认是否有类似的配置选项。
内容的提问来源于stack exchange,提问作者user2934930

