这个问题是关于这个问题“How to connect XMPP bosh server using java smack library?”
的前一个问题的扩展我使用Java作为服务器端语言。我已经使用smach-jbosh成功实现了xmpp BOSH连接,感谢@Deuteu帮助我实现这一目标,到目前为止,我修改了jbosh的BOSHClient.java
文件并添加了两个getter方法来提取RID和SID。
现在我的app服务器上有RID和SID(我正在使用Apache Tomcat)。我需要将此凭证传递给Strophe(Web客户端),以便它可以附加到连接。
我有一些疑问。
有人可以帮我解决这个问题吗?
答案 0 :(得分:4)
我相信@ fpsColton的回答是正确的 - 为了清晰起见,我只是添加了额外的信息。根据链接主题的要求,这里是我对此进行的代码更改 - 注意:我只添加了标有" DH"
的部分在BOSHConnection中:
// DH: function to preserve current api
public void login(String username, String password, String resource)
throws XMPPException {
login(username, password, resource, false);
}
// DH: Most of this is existing login function, but added prebind parameter
// to allow leaving function after all required pre-bind steps done and before
// presence stanza gets sent (sent from attach in XMPP client)
public void login(String username, String password, String resource, boolean preBind)
throws XMPPException {
if (!isConnected()) {
throw new IllegalStateException("Not connected to server.");
}
if (authenticated) {
throw new IllegalStateException("Already logged in to server.");
}
// Do partial version of nameprep on the username.
username = username.toLowerCase().trim();
String response;
if (config.isSASLAuthenticationEnabled()
&& saslAuthentication.hasNonAnonymousAuthentication()) {
// Authenticate using SASL
if (password != null) {
response = saslAuthentication.authenticate(username, password, resource);
} else {
response = saslAuthentication.authenticate(username, resource, config.getCallbackHandler());
}
} else {
// Authenticate using Non-SASL
response = new NonSASLAuthentication(this).authenticate(username, password, resource);
}
// Indicate that we're now authenticated.
authenticated = true;
anonymous = false;
// DH: Prebind only requires connect and authenticate
if (preBind) {
return;
}
// Set the user.
if (response != null) {
this.user = response;
// Update the serviceName with the one returned by the server
config.setServiceName(StringUtils.parseServer(response));
} else {
this.user = username + "@" + getServiceName();
if (resource != null) {
this.user += "/" + resource;
}
}
// Create the roster if it is not a reconnection.
if (this.roster == null) {
this.roster = new Roster(this);
}
if (config.isRosterLoadedAtLogin()) {
this.roster.reload();
}
// Set presence to online.
if (config.isSendPresence()) {
sendPacket(new Presence(Presence.Type.available));
}
// Stores the autentication for future reconnection
config.setLoginInfo(username, password, resource);
// If debugging is enabled, change the the debug window title to include
// the
// name we are now logged-in as.l
if (config.isDebuggerEnabled() && debugger != null) {
debugger.userHasLogged(user);
}
}
和
// DH
@Override
public void disconnect() {
client.close();
}
然后我的客户端(Web Server)包装类 - 用于从JSP内部进行连接:
注意:这是证明代码而非生产 - 所以这里有一些你可能不想要的东西。
public class SmackBoshConnector {
private String sessionID = null;
private String authID = null;
private Long requestID = 0L;
private String packetID = null;
private boolean connected = false;
public boolean connect(String userName, String password, String host, int port, final String xmppService) {
boolean success = false;
try {
Enumeration<SaslClientFactory> saslFacts = Sasl.getSaslClientFactories();
if (!saslFacts.hasMoreElements()) {
System.out.println("Sasl Provider not pre-loaded");
int added = Security.addProvider(new com.sun.security.sasl.Provider());
if (added == -1) {
System.out.println("Sasl Provider could not be loaded");
System.exit(added);
}
else {
System.out.println("Sasl Provider added");
}
}
BOSHConfiguration config = new BOSHConfiguration(false, host, port, "/http-bind/", xmppService);
BOSHConnection connection = new BOSHConnection(config);
PacketListener sndListener = new PacketListener() {
@Override
public void processPacket(Packet packet) {
SmackBoshConnector.this.packetID = packet.getPacketID();
System.out.println("Send PacketId["+packetID+"] to["+packet.toXML()+"]");
}
};
PacketListener rcvListener = new PacketListener() {
@Override
public void processPacket(Packet packet) {
SmackBoshConnector.this.packetID = packet.getPacketID();
System.out.println("Rcvd PacketId["+packetID+"] to["+packet.toXML()+"]");
}
};
PacketFilter packetFilter = new PacketFilter() {
@Override
public boolean accept(Packet packet) {
return true;
}
};
connection.addPacketSendingListener(sndListener, packetFilter);
connection.addPacketListener(rcvListener, packetFilter);
connection.connect();
// login with pre-bind only
connection.login(userName, password, "", true);
authID = connection.getConnectionID();
BOSHClient client = connection.getClient();
sessionID = client.getSid();
requestID = client.getRid();
System.out.println("Connected ["+authID+"] sid["+sessionID+"] rid["+requestID+"]");
success = true;
connected = true;
try {
Thread.yield();
Thread.sleep(500);
}
catch (InterruptedException e) {
// Ignore
}
finally {
connection.disconnect();
}
} catch (XMPPException ex) {
Logger.getLogger(SmackBoshConnector.class.getName()).log(Level.SEVERE, null, ex);
}
return success;
}
public boolean isConnected() {
return connected;
}
public String getSessionID() {
return sessionID;
}
public String getAuthID() {
return authID;
}
public String getRequestIDAsString() {
return Long.toString(requestID);
}
public String getNextRequestIDAsString() {
return Long.toString(requestID+1);
}
public static void main(String[] args) {
SmackBoshConnector bc = new SmackBoshConnector();
bc.connect("dazed", "i3ji44mj7k2qt14djct0t5o709", "192.168.2.15", 5280, "my.xmppservice.com");
}
}
我承认我没有完全记住为什么我把Thread.yield和Thread.sleep(1/2秒)放在这里 - 我想 - 正如你可以看到添加的PacketListener - 较低级别的函数在发送数据之后和从服务器返回响应之前返回 - 如果在服务器发送响应之前断开连接,那么它(也)会使它清理会话并且赢得了许多事情。工作。然而,正如@fpsColton所说,这可能是dicsonnect()实际上并不需要。
编辑:我现在记得更多关于whay我包括sleep()和yield()。我注意到Smack库在几个地方包含sleep(),包括source的XMPPConnection.shutdown()。另外就产量而言()我的环境中存在问题(Oracle数据库中的Java - 可能是非典型的),当它不包括在内时 - 按照Smack Forum Thread。
祝你好运。答案 1 :(得分:2)
使用smack创建了BOSH会话并提取了SID + RID值之后,需要将它们传递给Strophe的attach(),从这里开始你需要让strophe处理这个连接。 Strophe连接后,您不希望服务器对连接做任何事情。
如果您的服务器端代码在连接strophe之后向连接管理器发送任何消息,则很可能它会发送一个无效的RID,这将导致您的会话终止。
同样,一旦会话建立并且可以通过strophe使用,请不要尝试从服务器端继续使用它。在服务器端bosh客户端完成身份验证并且您已将SID + RID传递给页面之后,只需销毁服务器端连接对象,不要尝试断开连接或其他任何操作,因为这将终止您的会话。
您需要记住的是,与通过TCP的传统XMPP连接不同,BOSH客户端不保持与服务器的持久连接(这就是我们在Web应用程序中使用BOSH的原因)。所以没有什么可以断开的。持久连接实际上是在XMPP服务器和BOSH连接管理器之间,这不是您需要处理的事情。因此,当您从服务器端BOSH客户端调用disconnect时,您告诉连接管理器结束会话并关闭它与XMPP服务器的连接,这完全违背了创建会话的目的。