预先注意:我已经检查了stackoverflow上的其他线程,但没有找到类似的情况。 我们在生产服务器上面临着关于xmpp的奇怪问题。环境是这样的: 2个tomcats(v7),1个openfire(3.10),ngnix
我们有移动应用程序(android,ios)作为客户端,他们通过xmpp与我们的服务器通信。我们的服务器也是openfire(但具有管理员角色)的另一个用户,它通过SASL和自签名证书连接到openfire。它使用的是smack 4.1.0。
所以我们遇到了这个问题。在运行环境中一切顺利。客户端 - 服务器正在通信。但是当我们需要进行新的部署时,我们停止tomcat-deploy war-start tomcat(对于每个tomcat,这样我们就不会有停机时间)。服务器初始化没有问题。 Smack日志显示我已经与openfire建立了连接并进行了身份验证。此外,我可以看到来自客户端的聊天消息。但不知何故,服务器无法将消息发送回客户端。 在发送聊天消息时,不会抛出异常,就像它成功一样。但是在openfire上以节点形式发布内容(作为管理员角色)时,有以下内容:
*Unable to publish notification to node [NODENAME] , ex [org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 30000ms (~30s). Used filter: IQReplyFilter: iqAndIdFilter (AndFilter: (OrFilter: (IQTypeFilter: type=error, IQTypeFilter: type=result), StanzaIdFilter: id=H0ttG-44)), : fromFilter (OrFilter: (FromMatchesFilter (full): pubsub.SERVERNAME.com)).], cause [null], class [org.jivesoftware.smack.SmackException$NoResponseException]*
此问题持续约20-25分钟。后来某种程度上变得正常,客户端 - 服务器可以以两种方式进行通信。
连接侦听器上没有“连接丢失”或“重新连接”日志。我们发现没有任何有用的东西可以帮助我们在那里进行20分钟的通信是一种方式,然后在20-25分钟后就可以了。
以下是我们对xmpp连接的配置:
// We are using two-way authentication with certificates
SASLAuthentication.registerSASLMechanism(new SASLExternalMechanism());
XmppTrustManager xmppTrustManager = null;
try {
xmppTrustManager = new XmppTrustManager($truststore.path, $truststore.password);
} catch (final XMPPException e) {
log.error("Unable to create trust manager", e);
throw new...
}
final TrustManager[] trustManagers = new TrustManager[] { xmppTrustManager };
XmppKeyManager xmppKeyManager = null;
try {
xmppKeyManager = new XmppKeyManager($keystore.path, $keystore.password);
} catch (final XMPPException e) {
log.error("Unable to create key manager", e);
throw new ...
}
final KeyManager[] keyManagers = new KeyManager[] { xmppKeyManager };
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
} catch (final NoSuchAlgorithmException e) {
log.error("Cannot create SSLContext instance", e);
} catch (final KeyManagementException e) {
log.error("Cannot initialize SSLContext instance", e);
}
final XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setHost($host)
.setPort($port)
.setServiceName($domain).setCustomSSLContext(sslContext)
.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(final String hostname, final SSLSession session) {
return $domain.equals(hostname);
}
}).setDebuggerEnabled(false).allowEmptyOrNullUsernames().build();
final XMPPTCPConnection xmppConnection = new XMPPTCPConnection(config);
xmppConnection.setPacketReplyTimeout(30 * 1000);
// xmppConnection.addConnectionListener(connectionListener());
ReconnectionManager.getInstanceFor(xmppConnection).enableAutomaticReconnection();
xmppConnection.setUseStreamManagement(true);
xmppConnection.addConnectionListener(new ConnectionListener() {
@Override
public void reconnectionSuccessful() {
log.info("Successfully reconnected to the XMPP server.");
}
@Override
public void reconnectionFailed(final Exception e) {
log.info("Failed to reconnect to the XMPP server ", e.toString());
}
@Override
public void reconnectingIn(final int seconds) {
log.debug("Reconnecting in " + seconds + " seconds.");
}
@Override
public void connectionClosedOnError(final Exception e) {
log.info("Connection to XMPP server was lost ", e.toString());
}
@Override
public void connectionClosed() {
log.info("Connection to XMPP server was closed");
}
@Override
public void connected(final XMPPConnection connection) {
log.info("connected to XMPP server");
}
@Override
public void authenticated(final XMPPConnection connection, final boolean resumed) {
log.info("Xmpp connected authenticated. is resumed: " + resumed);
}
});
log.debug("xmppConnection bean is initialized");
return xmppConnection;
连接代码在onApplicationEvent(ContextRefreshedEvent事件)上:
if (connecting) {
return;
}
connecting = true;
try {
xmppConnection.connect();
xmppConnection.login("", "", "");
log.debug("no exception occured during connection");
} catch (XMPPException | SmackException | IOException e) {
// start a new thread that will try connecting every pingInterval seconds
new Thread(new Runnable() {
@Override
public void run() {
while (!xmppConnection.isConnected()) {
log.debug("waiting for a while to attempt login again");
try {
Thread.sleep(10 * 1000);
xmppConnection.connect();
xmppConnection.login("", "", "");
} catch (XMPPException | SmackException | IOException | InterruptedException e) {
...
}
}
}
}).start();
}
任何帮助将不胜感激。谢谢!